iphlpapi: Don't allocate gobs of memory when the ARP table is empty.
[wine.git] / dlls / iphlpapi / ipstats.c
blob3605d647235c8f9bb52681595f7a56b1c76a072c
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.
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43 #ifdef HAVE_NET_IF_H
44 #include <net/if.h>
45 #endif
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
48 #endif
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
51 #endif
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
54 #endif
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
57 #endif
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
61 #endif
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
64 #endif
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
67 #endif
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
71 #endif
73 #ifndef ROUNDUP
74 #define ROUNDUP(a) \
75 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
76 #endif
77 #ifndef ADVANCE
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
79 #endif
81 #include "windef.h"
82 #include "winbase.h"
83 #include "iprtrmib.h"
84 #include "ifenum.h"
85 #include "ipstats.h"
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
94 #define TCPS_CLOSED 7
95 #define TCPS_CLOSE_WAIT 8
96 #define TCPS_LAST_ACK 9
97 #define TCPS_LISTEN 10
98 #define TCPS_CLOSING 11
99 #endif
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
103 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
105 FILE *fp;
107 if (!name)
108 return ERROR_INVALID_PARAMETER;
109 if (!entry)
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");
115 if (fp) {
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))
123 ptr++;
124 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
125 nameFound = 1;
126 else
127 ptr = fgets(buf, sizeof(buf), fp);
129 if (nameFound) {
130 char *endPtr;
132 ptr += nameLen + 1;
133 if (ptr && *ptr) {
134 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
135 ptr = endPtr;
137 if (ptr && *ptr) {
138 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
139 ptr = endPtr;
141 if (ptr && *ptr) {
142 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
143 ptr = endPtr;
145 if (ptr && *ptr) {
146 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
147 ptr = endPtr;
149 if (ptr && *ptr) {
150 strtoul(ptr, &endPtr, 10); /* skip */
151 ptr = endPtr;
153 if (ptr && *ptr) {
154 strtoul(ptr, &endPtr, 10); /* skip */
155 ptr = endPtr;
157 if (ptr && *ptr) {
158 strtoul(ptr, &endPtr, 10); /* skip */
159 ptr = endPtr;
161 if (ptr && *ptr) {
162 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
163 ptr = endPtr;
165 if (ptr && *ptr) {
166 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
167 ptr = endPtr;
169 if (ptr && *ptr) {
170 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
171 ptr = endPtr;
173 if (ptr && *ptr) {
174 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
175 ptr = endPtr;
177 if (ptr && *ptr) {
178 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
179 ptr = endPtr;
182 fclose(fp);
184 else
186 ERR ("unimplemented!\n");
187 return ERROR_NOT_SUPPORTED;
190 return NO_ERROR;
193 DWORD getICMPStats(MIB_ICMP *stats)
195 FILE *fp;
197 if (!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");
203 if (fp) {
204 static const char hdr[] = "Icmp:";
205 char buf[512] = { 0 }, *ptr;
207 do {
208 ptr = fgets(buf, sizeof(buf), fp);
209 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
210 if (ptr) {
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) {
214 char *endPtr;
216 ptr += sizeof(hdr);
217 if (ptr && *ptr) {
218 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
219 ptr = endPtr;
221 if (ptr && *ptr) {
222 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
223 ptr = endPtr;
225 if (ptr && *ptr) {
226 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
227 ptr = endPtr;
229 if (ptr && *ptr) {
230 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
231 ptr = endPtr;
233 if (ptr && *ptr) {
234 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
235 ptr = endPtr;
237 if (ptr && *ptr) {
238 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
239 ptr = endPtr;
241 if (ptr && *ptr) {
242 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
243 ptr = endPtr;
245 if (ptr && *ptr) {
246 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
247 ptr = endPtr;
249 if (ptr && *ptr) {
250 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
251 ptr = endPtr;
253 if (ptr && *ptr) {
254 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
255 ptr = endPtr;
257 if (ptr && *ptr) {
258 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
259 ptr = endPtr;
261 if (ptr && *ptr) {
262 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
263 ptr = endPtr;
265 if (ptr && *ptr) {
266 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
267 ptr = endPtr;
269 if (ptr && *ptr) {
270 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
271 ptr = endPtr;
273 if (ptr && *ptr) {
274 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
275 ptr = endPtr;
277 if (ptr && *ptr) {
278 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
279 ptr = endPtr;
281 if (ptr && *ptr) {
282 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
283 ptr = endPtr;
285 if (ptr && *ptr) {
286 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
287 ptr = endPtr;
289 if (ptr && *ptr) {
290 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
291 ptr = endPtr;
293 if (ptr && *ptr) {
294 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
295 ptr = endPtr;
297 if (ptr && *ptr) {
298 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
299 ptr = endPtr;
301 if (ptr && *ptr) {
302 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
303 ptr = endPtr;
305 if (ptr && *ptr) {
306 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
307 ptr = endPtr;
309 if (ptr && *ptr) {
310 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
311 ptr = endPtr;
315 fclose(fp);
317 else
319 ERR ("unimplemented!\n");
320 return ERROR_NOT_SUPPORTED;
323 return NO_ERROR;
326 DWORD getIPStats(PMIB_IPSTATS stats)
328 FILE *fp;
330 if (!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");
339 if (fp) {
340 static const char hdr[] = "Ip:";
341 char buf[512] = { 0 }, *ptr;
343 do {
344 ptr = fgets(buf, sizeof(buf), fp);
345 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
346 if (ptr) {
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) {
350 char *endPtr;
352 ptr += sizeof(hdr);
353 if (ptr && *ptr) {
354 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
355 ptr = endPtr;
357 if (ptr && *ptr) {
358 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
359 ptr = endPtr;
361 if (ptr && *ptr) {
362 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
363 ptr = endPtr;
365 if (ptr && *ptr) {
366 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
367 ptr = endPtr;
369 if (ptr && *ptr) {
370 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
371 ptr = endPtr;
373 if (ptr && *ptr) {
374 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
375 ptr = endPtr;
377 if (ptr && *ptr) {
378 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
379 ptr = endPtr;
381 if (ptr && *ptr) {
382 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
383 ptr = endPtr;
385 if (ptr && *ptr) {
386 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
387 ptr = endPtr;
389 if (ptr && *ptr) {
390 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
391 ptr = endPtr;
393 if (ptr && *ptr) {
394 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
395 ptr = endPtr;
397 if (ptr && *ptr) {
398 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
399 ptr = endPtr;
401 if (ptr && *ptr) {
402 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
403 ptr = endPtr;
405 if (ptr && *ptr) {
406 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
407 ptr = endPtr;
409 if (ptr && *ptr) {
410 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
411 ptr = endPtr;
413 if (ptr && *ptr) {
414 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
415 ptr = endPtr;
417 if (ptr && *ptr) {
418 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
419 ptr = endPtr;
421 if (ptr && *ptr) {
422 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
423 ptr = endPtr;
425 if (ptr && *ptr) {
426 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
427 ptr = endPtr;
429 /* hmm, no routingDiscards */
432 fclose(fp);
434 else
436 ERR ("unimplemented!\n");
437 return ERROR_NOT_SUPPORTED;
440 return NO_ERROR;
443 DWORD getTCPStats(MIB_TCPSTATS *stats)
445 FILE *fp;
447 if (!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");
454 if (fp) {
455 static const char hdr[] = "Tcp:";
456 char buf[512] = { 0 }, *ptr;
459 do {
460 ptr = fgets(buf, sizeof(buf), fp);
461 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
462 if (ptr) {
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) {
466 char *endPtr;
468 ptr += sizeof(hdr);
469 if (ptr && *ptr) {
470 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
471 ptr = endPtr;
473 if (ptr && *ptr) {
474 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
475 ptr = endPtr;
477 if (ptr && *ptr) {
478 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
479 ptr = endPtr;
481 if (ptr && *ptr) {
482 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
483 ptr = endPtr;
485 if (ptr && *ptr) {
486 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
487 ptr = endPtr;
489 if (ptr && *ptr) {
490 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
491 ptr = endPtr;
493 if (ptr && *ptr) {
494 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
495 ptr = endPtr;
497 if (ptr && *ptr) {
498 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
499 ptr = endPtr;
501 if (ptr && *ptr) {
502 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
503 ptr = endPtr;
505 if (ptr && *ptr) {
506 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
507 ptr = endPtr;
509 if (ptr && *ptr) {
510 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
511 ptr = endPtr;
513 if (ptr && *ptr) {
514 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
515 ptr = endPtr;
517 if (ptr && *ptr) {
518 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
519 ptr = endPtr;
521 if (ptr && *ptr) {
522 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
523 ptr = endPtr;
525 stats->dwNumConns = getNumTcpEntries();
528 fclose(fp);
530 else
532 ERR ("unimplemented!\n");
533 return ERROR_NOT_SUPPORTED;
536 return NO_ERROR;
539 DWORD getUDPStats(MIB_UDPSTATS *stats)
541 FILE *fp;
543 if (!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");
550 if (fp) {
551 static const char hdr[] = "Udp:";
552 char buf[512] = { 0 }, *ptr;
555 do {
556 ptr = fgets(buf, sizeof(buf), fp);
557 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
558 if (ptr) {
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) {
562 char *endPtr;
564 ptr += sizeof(hdr);
565 if (ptr && *ptr) {
566 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
567 ptr = endPtr;
569 if (ptr && *ptr) {
570 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
571 ptr = endPtr;
573 if (ptr && *ptr) {
574 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
575 ptr = endPtr;
577 if (ptr && *ptr) {
578 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
579 ptr = endPtr;
581 if (ptr && *ptr) {
582 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
583 ptr = endPtr;
587 fclose(fp);
589 else
591 ERR ("unimplemented!\n");
592 return ERROR_NOT_SUPPORTED;
595 return NO_ERROR;
598 static DWORD getNumWithOneHeader(const char *filename)
600 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
601 size_t Len = 0;
602 char *Buf;
603 struct xinpgen *pXIG, *pOrigXIG;
604 int Protocol;
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;
611 else
613 ERR ("Unsupported mib '%s', needs protocol mapping\n",
614 filename);
615 return 0;
618 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
620 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
621 return 0;
624 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
625 if (!Buf)
627 ERR ("Out of memory!\n");
628 return 0;
631 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
633 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
634 HeapFree (GetProcessHeap (), 0, Buf);
635 return 0;
638 /* Might be nothing here; first entry is just a header it seems */
639 if (Len <= sizeof (struct xinpgen))
641 HeapFree (GetProcessHeap (), 0, Buf);
642 return 0;
645 pOrigXIG = (struct xinpgen *)Buf;
646 pXIG = pOrigXIG;
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;
662 else
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)
670 continue;
672 /* Ignore PCBs that were freed while generating the data */
673 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
674 continue;
676 /* we're only interested in IPv4 addresses */
677 if (!(pINData->inp_vflag & INP_IPV4) ||
678 (pINData->inp_vflag & INP_IPV6))
679 continue;
681 /* If all 0's, skip it */
682 if (!pINData->inp_laddr.s_addr &&
683 !pINData->inp_lport &&
684 !pINData->inp_faddr.s_addr &&
685 !pINData->inp_fport)
686 continue;
688 NumEntries++;
691 HeapFree (GetProcessHeap (), 0, Buf);
692 return NumEntries;
693 #else
694 FILE *fp;
695 int ret = 0;
697 fp = fopen(filename, "r");
698 if (fp) {
699 char buf[512] = { 0 }, *ptr;
702 ptr = fgets(buf, sizeof(buf), fp);
703 if (ptr) {
704 do {
705 ptr = fgets(buf, sizeof(buf), fp);
706 if (ptr)
707 ret++;
708 } while (ptr);
710 fclose(fp);
712 else
713 ERR ("Unable to open '%s' to count entries!\n", filename);
715 return ret;
716 #endif
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};
723 size_t needed;
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");
731 return 0;
734 buf = HeapAlloc (GetProcessHeap (), 0, needed);
735 if (!buf) return 0;
737 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
739 ERR ("sysctl 2 failed!\n");
740 HeapFree (GetProcessHeap (), 0, buf);
741 return 0;
744 lim = buf + needed;
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",
752 rtm->rtm_type);
753 continue;
756 /* Ignore all entries except for gateway routes which aren't
757 multicast */
758 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
759 continue;
761 RouteCount++;
764 HeapFree (GetProcessHeap (), 0, buf);
765 return RouteCount;
766 #else
767 return getNumWithOneHeader("/proc/net/route");
768 #endif
771 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
772 DWORD flags)
774 DWORD ret;
776 if (!ppIpForwardTable)
777 ret = ERROR_INVALID_PARAMETER;
778 else {
779 DWORD numRoutes = getNumRoutes();
780 DWORD size = sizeof(MIB_IPFORWARDTABLE);
781 PMIB_IPFORWARDTABLE table;
783 if (numRoutes > 1)
784 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
785 table = HeapAlloc(heap, flags, size);
786 if (table) {
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};
789 size_t needed;
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);
797 return NO_ERROR;
800 buf = HeapAlloc (GetProcessHeap (), 0, needed);
801 if (!buf)
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);
812 return NO_ERROR;
815 *ppIpForwardTable = table;
816 table->dwNumEntries = 0;
818 lim = buf + needed;
819 for (next = buf; next < lim; next += rtm->rtm_msglen)
821 int i;
823 rtm = (struct rt_msghdr *)next;
825 if (rtm->rtm_type != RTM_GET)
827 WARN ("Got unexpected message type 0x%x!\n",
828 rtm->rtm_type);
829 continue;
832 /* Ignore all entries except for gateway routes which aren't
833 multicast */
834 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
835 (rtm->rtm_flags & RTF_MULTICAST))
836 continue;
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 =
846 MIB_IPPROTO_LOCAL;
848 addrPtr = (char *)(rtm + 1);
850 for (i = 1; i; i <<= 1)
852 struct sockaddr *sa;
853 DWORD addr;
855 if (!(i & rtm->rtm_addrs))
856 continue;
858 sa = (struct sockaddr *)addrPtr;
859 ADVANCE (addrPtr, sa);
861 /* default routes are encoded by length-zero sockaddr */
862 if (sa->sa_len == 0)
863 addr = 0;
864 else if (sa->sa_family != AF_INET)
866 ERR ("Received unsupported sockaddr family 0x%x\n",
867 sa->sa_family);
868 addr = 0;
870 else
872 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
874 addr = sin->sin_addr.s_addr;
877 switch (i)
879 case RTA_DST:
880 table->table[table->dwNumEntries].dwForwardDest = addr;
881 break;
883 case RTA_GATEWAY:
884 table->table[table->dwNumEntries].dwForwardNextHop = addr;
885 break;
887 case RTA_NETMASK:
888 table->table[table->dwNumEntries].dwForwardMask = addr;
889 break;
891 default:
892 ERR ("Unexpected address type 0x%x\n", i);
896 table->dwNumEntries++;
899 HeapFree (GetProcessHeap (), 0, buf);
900 ret = NO_ERROR;
901 #else
902 FILE *fp;
904 ret = NO_ERROR;
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");
909 if (fp) {
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);
918 if (ptr) {
919 DWORD index;
921 while (!isspace(*ptr))
922 ptr++;
923 *ptr = '\0';
924 ptr++;
925 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
926 char *endPtr;
928 table->table[table->dwNumEntries].dwForwardIfIndex = index;
929 if (*ptr) {
930 table->table[table->dwNumEntries].dwForwardDest =
931 strtoul(ptr, &endPtr, 16);
932 ptr = endPtr;
934 if (ptr && *ptr) {
935 table->table[table->dwNumEntries].dwForwardNextHop =
936 strtoul(ptr, &endPtr, 16);
937 ptr = endPtr;
939 if (ptr && *ptr) {
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;
948 else
949 table->table[table->dwNumEntries].dwForwardType =
950 MIB_IPROUTE_TYPE_DIRECT;
951 ptr = endPtr;
953 if (ptr && *ptr) {
954 strtoul(ptr, &endPtr, 16); /* refcount, skip */
955 ptr = endPtr;
957 if (ptr && *ptr) {
958 strtoul(ptr, &endPtr, 16); /* use, skip */
959 ptr = endPtr;
961 if (ptr && *ptr) {
962 table->table[table->dwNumEntries].dwForwardMetric1 =
963 strtoul(ptr, &endPtr, 16);
964 ptr = endPtr;
966 if (ptr && *ptr) {
967 table->table[table->dwNumEntries].dwForwardMask =
968 strtoul(ptr, &endPtr, 16);
969 ptr = endPtr;
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 =
974 MIB_IPPROTO_LOCAL;
975 table->dwNumEntries++;
979 fclose(fp);
981 else
983 ERR ("unimplemented!\n");
984 return ERROR_NOT_SUPPORTED;
986 #endif
988 else
989 ret = ERROR_OUTOFMEMORY;
991 return ret;
994 DWORD getNumArpEntries(void)
996 return getNumWithOneHeader("/proc/net/arp");
999 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1001 DWORD ret;
1003 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1004 ERR ("unimplemented!\n");
1005 return ERROR_NOT_SUPPORTED;
1006 #endif
1008 if (!ppIpNetTable)
1009 ret = ERROR_INVALID_PARAMETER;
1010 else {
1011 DWORD numEntries = getNumArpEntries();
1012 DWORD size = sizeof(MIB_IPNETTABLE);
1013 PMIB_IPNETTABLE table;
1015 if (numEntries > 1)
1016 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1017 table = HeapAlloc(heap, flags, size);
1018 if (table) {
1019 FILE *fp;
1021 ret = NO_ERROR;
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");
1026 if (fp) {
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);
1033 if (ptr) {
1034 char *endPtr;
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))
1039 ptr++;
1041 if (ptr && *ptr) {
1042 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1043 ptr = endPtr;
1045 if (ptr && *ptr) {
1046 DWORD flags = strtoul(ptr, &endPtr, 16);
1048 #ifdef ATF_COM
1049 if (flags & ATF_COM)
1050 table->table[table->dwNumEntries].dwType =
1051 MIB_IPNET_TYPE_DYNAMIC;
1052 else
1053 #endif
1054 #ifdef ATF_PERM
1055 if (flags & ATF_PERM)
1056 table->table[table->dwNumEntries].dwType =
1057 MIB_IPNET_TYPE_STATIC;
1058 else
1059 #endif
1060 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1062 ptr = endPtr;
1064 while (ptr && *ptr && isspace(*ptr))
1065 ptr++;
1066 while (ptr && *ptr && !isspace(*ptr)) {
1067 DWORD byte = strtoul(ptr, &endPtr, 16);
1069 if (endPtr && *endPtr) {
1070 endPtr++;
1071 table->table[table->dwNumEntries].bPhysAddr[
1072 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1073 byte & 0x0ff;
1075 ptr = endPtr;
1077 if (ptr && *ptr) {
1078 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1079 ptr = endPtr;
1081 getInterfaceIndexByName(ptr,
1082 &table->table[table->dwNumEntries].dwIndex);
1083 table->dwNumEntries++;
1086 fclose(fp);
1088 else
1089 ret = ERROR_NOT_SUPPORTED;
1091 else
1092 ret = ERROR_OUTOFMEMORY;
1094 return ret;
1097 DWORD getNumUdpEntries(void)
1099 return getNumWithOneHeader("/proc/net/udp");
1102 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1104 DWORD ret;
1106 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1107 ERR ("unimplemented!\n");
1108 return ERROR_NOT_SUPPORTED;
1109 #endif
1111 if (!ppUdpTable)
1112 ret = ERROR_INVALID_PARAMETER;
1113 else {
1114 DWORD numEntries = getNumUdpEntries();
1115 PMIB_UDPTABLE table = HeapAlloc(heap, flags,
1116 sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
1118 if (table) {
1119 FILE *fp;
1121 ret = NO_ERROR;
1122 *ppUdpTable = table;
1123 table->dwNumEntries = 0;
1124 /* get from /proc/net/udp, no error if can't */
1125 fp = fopen("/proc/net/udp", "r");
1126 if (fp) {
1127 char buf[512] = { 0 }, *ptr;
1129 /* skip header line */
1130 ptr = fgets(buf, sizeof(buf), fp);
1131 while (ptr && table->dwNumEntries < numEntries) {
1132 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1133 ptr = fgets(buf, sizeof(buf), fp);
1134 if (ptr) {
1135 char *endPtr;
1137 if (ptr && *ptr) {
1138 strtoul(ptr, &endPtr, 16); /* skip */
1139 ptr = endPtr;
1141 if (ptr && *ptr) {
1142 ptr++;
1143 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1144 &endPtr, 16);
1145 ptr = endPtr;
1147 if (ptr && *ptr) {
1148 ptr++;
1149 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1150 &endPtr, 16);
1151 ptr = endPtr;
1153 table->dwNumEntries++;
1156 fclose(fp);
1158 else
1159 ret = ERROR_NOT_SUPPORTED;
1161 else
1162 ret = ERROR_OUTOFMEMORY;
1164 return ret;
1168 DWORD getNumTcpEntries(void)
1170 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1171 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1172 #else
1173 return getNumWithOneHeader ("/proc/net/tcp");
1174 #endif
1178 /* Why not a lookup table? Because the TCPS_* constants are different
1179 on different platforms */
1180 static DWORD TCPStateToMIBState (int state)
1182 switch (state)
1184 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1185 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1186 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1187 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1188 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1189 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1190 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1191 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1192 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1193 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1194 default:
1195 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1200 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1201 DWORD flags)
1203 DWORD numEntries;
1204 PMIB_TCPTABLE table;
1205 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1206 size_t Len = 0;
1207 char *Buf;
1208 struct xinpgen *pXIG, *pOrigXIG;
1209 #else
1210 FILE *fp;
1211 char buf[512] = { 0 }, *ptr;
1212 #endif
1214 if (!ppTcpTable)
1215 return ERROR_INVALID_PARAMETER;
1217 numEntries = getNumTcpEntries ();
1219 if (!*ppTcpTable)
1221 DWORD size = sizeof(MIB_TCPTABLE);
1223 if (numEntries > 1)
1224 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1225 *ppTcpTable = HeapAlloc (heap, flags, size);
1226 if (!*ppTcpTable)
1228 ERR ("Out of memory!\n");
1229 return ERROR_OUTOFMEMORY;
1231 maxEntries = numEntries;
1234 table = *ppTcpTable;
1235 table->dwNumEntries = 0;
1236 if (!numEntries)
1237 return NO_ERROR;
1239 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1241 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1243 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1244 return ERROR_OUTOFMEMORY;
1247 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1248 if (!Buf)
1250 ERR ("Out of memory!\n");
1251 return ERROR_OUTOFMEMORY;
1254 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1256 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1257 HeapFree (GetProcessHeap (), 0, Buf);
1258 return ERROR_OUTOFMEMORY;
1261 /* Might be nothing here; first entry is just a header it seems */
1262 if (Len <= sizeof (struct xinpgen))
1264 HeapFree (GetProcessHeap (), 0, Buf);
1265 return NO_ERROR;
1268 pOrigXIG = (struct xinpgen *)Buf;
1269 pXIG = pOrigXIG;
1271 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1272 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1273 (table->dwNumEntries < maxEntries);
1274 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1276 struct tcpcb *pTCPData = NULL;
1277 struct inpcb *pINData;
1278 struct xsocket *pSockData;
1280 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1281 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1282 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1284 /* Ignore sockets for other protocols */
1285 if (pSockData->xso_protocol != IPPROTO_TCP)
1286 continue;
1288 /* Ignore PCBs that were freed while generating the data */
1289 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1290 continue;
1292 /* we're only interested in IPv4 addresses */
1293 if (!(pINData->inp_vflag & INP_IPV4) ||
1294 (pINData->inp_vflag & INP_IPV6))
1295 continue;
1297 /* If all 0's, skip it */
1298 if (!pINData->inp_laddr.s_addr &&
1299 !pINData->inp_lport &&
1300 !pINData->inp_faddr.s_addr &&
1301 !pINData->inp_fport)
1302 continue;
1304 /* Fill in structure details */
1305 table->table[table->dwNumEntries].dwLocalAddr =
1306 pINData->inp_laddr.s_addr;
1307 table->table[table->dwNumEntries].dwLocalPort =
1308 pINData->inp_lport;
1309 table->table[table->dwNumEntries].dwRemoteAddr =
1310 pINData->inp_faddr.s_addr;
1311 table->table[table->dwNumEntries].dwRemotePort =
1312 pINData->inp_fport;
1313 table->table[table->dwNumEntries].dwState =
1314 TCPStateToMIBState (pTCPData->t_state);
1316 table->dwNumEntries++;
1319 HeapFree (GetProcessHeap (), 0, Buf);
1320 #else
1321 /* get from /proc/net/tcp, no error if can't */
1322 fp = fopen("/proc/net/tcp", "r");
1323 if (!fp)
1324 return ERROR_NOT_SUPPORTED;
1326 /* skip header line */
1327 ptr = fgets(buf, sizeof(buf), fp);
1328 while (ptr && table->dwNumEntries < maxEntries) {
1329 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1330 ptr = fgets(buf, sizeof(buf), fp);
1331 if (ptr) {
1332 char *endPtr;
1334 while (ptr && *ptr && *ptr != ':')
1335 ptr++;
1336 if (ptr && *ptr)
1337 ptr++;
1338 if (ptr && *ptr) {
1339 table->table[table->dwNumEntries].dwLocalAddr =
1340 strtoul(ptr, &endPtr, 16);
1341 ptr = endPtr;
1343 if (ptr && *ptr) {
1344 ptr++;
1345 table->table[table->dwNumEntries].dwLocalPort =
1346 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1347 ptr = endPtr;
1349 if (ptr && *ptr) {
1350 table->table[table->dwNumEntries].dwRemoteAddr =
1351 strtoul(ptr, &endPtr, 16);
1352 ptr = endPtr;
1354 if (ptr && *ptr) {
1355 ptr++;
1356 table->table[table->dwNumEntries].dwRemotePort =
1357 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1358 ptr = endPtr;
1360 if (ptr && *ptr) {
1361 DWORD state = strtoul(ptr, &endPtr, 16);
1363 table->table[table->dwNumEntries].dwState =
1364 TCPStateToMIBState (state);
1365 ptr = endPtr;
1367 table->dwNumEntries++;
1370 fclose(fp);
1371 #endif
1373 return NO_ERROR;