1 /*
2  *  UDP MIB group Table implementation - udpTable.c
3  *
4  */
5 
6 /* Portions of this file are subject to the following copyright(s).  See
7  * the Net-SNMP's COPYING file for more details and other copyrights
8  * that may apply:
9  */
10 /*
11  * Portions of this file are copyrighted by:
12  * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
13  * Use is subject to license terms specified in the COPYING file
14  * distributed with the Net-SNMP package.
15  */
16 
17 #include <net-snmp/net-snmp-config.h>
18 #include "mibII_common.h"
19 
20 #if HAVE_NETINET_UDP_H
21 #include <netinet/udp.h>
22 #endif
23 #if HAVE_NETINET_UDP_VAR_H
24 #include <netinet/udp_var.h>
25 #endif
26 
27 #if HAVE_KVM_GETFILES
28 #if defined(HAVE_KVM_GETFILE2) || !defined(openbsd5)
29 #undef HAVE_KVM_GETFILES
30 #endif
31 #endif
32 
33 #if HAVE_KVM_GETFILES
34 #include <kvm.h>
35 #include <sys/sysctl.h>
36 #define _KERNEL
37 #include <sys/file.h>
38 #undef _KERNEL
39 #endif
40 
41 #if defined(cygwin) || defined(mingw32)
42 #include <winerror.h>
43 #endif
44 
45 #include <net-snmp/net-snmp-includes.h>
46 #include <net-snmp/agent/net-snmp-agent-includes.h>
47 #include <net-snmp/agent/auto_nlist.h>
48 
49 #ifdef linux
50 #include "tcpTable.h"
51 #endif
52 #include "udp.h"
53 #include "udpTable.h"
54 
55 #ifdef hpux11
56 #define	UDPTABLE_ENTRY_TYPE	mib_udpLsnEnt
57 #define	UDPTABLE_LOCALADDRESS	LocalAddress
58 #define	UDPTABLE_LOCALPORT	LocalPort
59 #define	UDPTABLE_IS_TABLE
60 
61 #elif defined(solaris2)
62 typedef struct netsnmp_udpEntry_s netsnmp_udpEntry;
63 struct netsnmp_udpEntry_s {
64     mib2_udpEntry_t   entry;
65     netsnmp_udpEntry *inp_next;
66 };
67 #define	UDPTABLE_ENTRY_TYPE	netsnmp_udpEntry
68 #define	UDPTABLE_LOCALADDRESS	entry.udpLocalAddress
69 #define	UDPTABLE_LOCALPORT	entry.udpLocalPort
70 #define	UDPTABLE_IS_LINKED_LIST
71 
72 #elif defined(HAVE_IPHLPAPI_H)
73 #include <iphlpapi.h>
74 #define	UDPTABLE_ENTRY_TYPE	MIB_UDPROW		/* ??? */
75 #define	UDPTABLE_LOCALADDRESS	dwLocalAddr
76 #define	UDPTABLE_LOCALPORT	dwLocalPort
77 #define	UDPTABLE_IS_TABLE
78 
79 #elif defined(HAVE_KVM_GETFILES)
80 #define	UDPTABLE_ENTRY_TYPE	struct kinfo_file
81 #define	UDPTABLE_LOCALADDRESS	inp_laddru[0]
82 #define	UDPTABLE_LOCALPORT	inp_lport
83 #define	UDPTABLE_IS_TABLE
84 
85 #elif defined(linux)
86 #define INP_NEXT_SYMBOL		inp_next
87 #define	UDPTABLE_ENTRY_TYPE	struct inpcb
88 #define	UDPTABLE_LOCALADDRESS	inp_laddr.s_addr
89 #define	UDPTABLE_LOCALPORT	inp_lport
90 #define	UDPTABLE_IS_LINKED_LIST
91 
92 #else
93 #ifdef openbsd4
94 #define INP_NEXT_SYMBOL		inp_queue.cqe_next	/* or set via <net-snmp/system/openbsd.h> */
95 #endif
96 
97 #if defined(freebsd4) || defined(darwin) || defined(osf5)
98 typedef struct netsnmp_inpcb_s netsnmp_inpcb;
99 struct netsnmp_inpcb_s {
100 #if __FreeBSD_version >= 1200026
101     struct xinpcb   pcb;
102 #else
103     struct inpcb    pcb;
104 #endif
105     int             state;
106     netsnmp_inpcb  *inp_next;
107 };
108 #define	UDPTABLE_ENTRY_TYPE	netsnmp_inpcb
109 #define	UDPTABLE_LOCALADDRESS	pcb.inp_laddr.s_addr
110 #define	UDPTABLE_LOCALPORT	pcb.inp_lport
111 #else
112 #define	UDPTABLE_ENTRY_TYPE	struct inpcb
113 #define	UDPTABLE_LOCALADDRESS	inp_laddr.s_addr
114 #define	UDPTABLE_LOCALPORT	inp_lport
115 #endif
116 #define	UDPTABLE_IS_LINKED_LIST
117 
118 #endif                          /* hpux11 */
119 
120 				/* Head of linked list, or root of table */
121 UDPTABLE_ENTRY_TYPE	*udp_head  = NULL;
122 int                      udp_size  = 0;	/* Only used for table-based systems */
123 
124 
125 	/*
126 	 *
127 	 * Initialization and handler routines are common to all architectures
128 	 *
129 	 */
130 #ifndef MIB_STATS_CACHE_TIMEOUT
131 #define MIB_STATS_CACHE_TIMEOUT	5
132 #endif
133 #ifndef UDP_STATS_CACHE_TIMEOUT
134 #define UDP_STATS_CACHE_TIMEOUT	MIB_STATS_CACHE_TIMEOUT
135 #endif
136 
137 #ifdef UDP_ADDRESSES_IN_HOST_ORDER
138 #define UDP_ADDRESS_TO_HOST_ORDER(x) x
139 #define UDP_ADDRESS_TO_NETWORK_ORDER(x) htonl(x)
140 #else
141 #define UDP_ADDRESS_TO_HOST_ORDER(x) ntohl(x)
142 #define UDP_ADDRESS_TO_NETWORK_ORDER(x) x
143 #endif
144 
145 #ifdef UDP_PORTS_IN_HOST_ORDER
146 #define UDP_PORT_TO_HOST_ORDER(x) x
147 #else
148 #define UDP_PORT_TO_HOST_ORDER(x) ntohs(x)
149 #endif
150 
151 
152 oid             udpTable_oid[] = { SNMP_OID_MIB2, 7, 5 };
153 
154 void
init_udpTable(void)155 init_udpTable(void)
156 {
157     netsnmp_table_registration_info *table_info;
158     netsnmp_iterator_info           *iinfo;
159     netsnmp_handler_registration    *reginfo;
160     int                              rc;
161 
162     DEBUGMSGTL(("mibII/udpTable", "Initialising UDP Table\n"));
163     /*
164      * Create the table data structure, and define the indexing....
165      */
166     table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
167     if (!table_info) {
168         return;
169     }
170     netsnmp_table_helper_add_indexes(table_info, ASN_IPADDRESS,
171                                                  ASN_INTEGER, 0);
172     table_info->min_column = UDPLOCALADDRESS;
173     table_info->max_column = UDPLOCALPORT;
174 
175 
176     /*
177      * .... and iteration information ....
178      */
179     iinfo      = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
180     if (!iinfo) {
181         netsnmp_table_registration_info_free(table_info);
182         return;
183     }
184     iinfo->get_first_data_point = udpTable_first_entry;
185     iinfo->get_next_data_point  = udpTable_next_entry;
186     iinfo->table_reginfo        = table_info;
187 #if defined (WIN32) || defined (cygwin)
188     iinfo->flags               |= NETSNMP_ITERATOR_FLAG_SORTED;
189 #endif /* WIN32 || cygwin */
190 
191 
192     /*
193      * .... and register the table with the agent.
194      */
195     reginfo = netsnmp_create_handler_registration("udpTable",
196             udpTable_handler,
197             udpTable_oid, OID_LENGTH(udpTable_oid),
198             HANDLER_CAN_RONLY),
199     rc = netsnmp_register_table_iterator2(reginfo, iinfo);
200     if (rc != SNMPERR_SUCCESS)
201         return;
202 
203     /*
204      * .... with a local cache
205      */
206     netsnmp_inject_handler( reginfo,
207 		    netsnmp_get_cache_handler(UDP_STATS_CACHE_TIMEOUT,
208 			   		udpTable_load, udpTable_free,
209 					udpTable_oid, OID_LENGTH(udpTable_oid)));
210 }
211 
212 
213 
214 int
udpTable_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)215 udpTable_handler(netsnmp_mib_handler          *handler,
216                  netsnmp_handler_registration *reginfo,
217                  netsnmp_agent_request_info   *reqinfo,
218                  netsnmp_request_info         *requests)
219 {
220     netsnmp_request_info  *request;
221     netsnmp_variable_list *requestvb;
222     netsnmp_table_request_info *table_info;
223     UDPTABLE_ENTRY_TYPE	  *entry;
224     oid      subid;
225     long     port;
226     in_addr_t addr;
227 
228     DEBUGMSGTL(("mibII/udpTable", "Handler - mode %s\n",
229                     se_find_label_in_slist("agent_mode", reqinfo->mode)));
230     switch (reqinfo->mode) {
231     case MODE_GET:
232         for (request=requests; request; request=request->next) {
233             requestvb = request->requestvb;
234             DEBUGMSGTL(( "mibII/udpTable", "oid: "));
235             DEBUGMSGOID(("mibII/udpTable", requestvb->name,
236                                            requestvb->name_length));
237             DEBUGMSG((   "mibII/udpTable", "\n"));
238 
239             entry = (UDPTABLE_ENTRY_TYPE *)netsnmp_extract_iterator_context(request);
240             if (!entry)
241                 continue;
242             table_info = netsnmp_extract_table_info(request);
243             subid      = table_info->colnum;
244 
245             switch (subid) {
246             case UDPLOCALADDRESS:
247 #if defined(osf5) && defined(IN6_EXTRACT_V4ADDR)
248                 addr = ntohl(IN6_EXTRACT_V4ADDR(&entry->pcb.inp_laddr));
249 	        snmp_set_var_typed_value(requestvb, ASN_IPADDRESS,
250                                          (u_char*)&addr,
251                                          sizeof(uint32_t));
252 #else
253                 addr = UDP_ADDRESS_TO_HOST_ORDER(entry->UDPTABLE_LOCALADDRESS);
254 	        snmp_set_var_typed_value(requestvb, ASN_IPADDRESS,
255                                          (u_char *)&addr,
256                                          sizeof(uint32_t));
257 #endif
258                 break;
259             case UDPLOCALPORT:
260                 port = UDP_PORT_TO_HOST_ORDER((u_short)entry->UDPTABLE_LOCALPORT);
261 	        snmp_set_var_typed_value(requestvb, ASN_INTEGER,
262                                  (u_char *)&port, sizeof(port));
263                 break;
264 	    }
265 	}
266         break;
267 
268     case MODE_GETNEXT:
269     case MODE_GETBULK:
270 #ifndef NETSNMP_NO_WRITE_SUPPORT
271     case MODE_SET_RESERVE1:
272     case MODE_SET_RESERVE2:
273     case MODE_SET_ACTION:
274     case MODE_SET_COMMIT:
275     case MODE_SET_FREE:
276     case MODE_SET_UNDO:
277 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
278         snmp_log(LOG_WARNING, "mibII/udpTable: Unsupported mode (%d)\n",
279                                reqinfo->mode);
280         break;
281     default:
282         snmp_log(LOG_WARNING, "mibII/udpTable: Unrecognised mode (%d)\n",
283                                reqinfo->mode);
284         break;
285     }
286 
287     return SNMP_ERR_NOERROR;
288 }
289 
290 	/*
291 	 * Two forms of iteration hook routines:
292 	 *    One for when the UDP table is stored as a table
293 	 *    One for when the UDP table is stored as a linked list
294 	 *
295 	 * Also applies to the cache-handler free routine
296 	 */
297 
298 #ifdef	UDPTABLE_IS_TABLE
299 netsnmp_variable_list *
udpTable_first_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)300 udpTable_first_entry(void **loop_context,
301                      void **data_context,
302                      netsnmp_variable_list *index,
303                      netsnmp_iterator_info *data)
304 {
305     /*
306      * XXX - How can we tell if the cache is valid?
307      *       No access to 'reqinfo'
308      */
309     if (udp_size == 0)
310         return NULL;
311 
312     /*
313      * Point to the first entry, and use the
314      * 'next_entry' hook to retrieve this row
315      */
316     *loop_context = 0;
317     return udpTable_next_entry( loop_context, data_context, index, data );
318 }
319 
320 netsnmp_variable_list *
udpTable_next_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)321 udpTable_next_entry( void **loop_context,
322                      void **data_context,
323                      netsnmp_variable_list *index,
324                      netsnmp_iterator_info *data)
325 {
326     int i = (intptr_t)*loop_context;
327     long port;
328 
329 #if HAVE_KVM_GETFILES
330     while (i < udp_size && (udp_head[i].so_protocol != IPPROTO_UDP
331 	    || udp_head[i].so_family != AF_INET))
332 	i++;
333 #endif
334     if (udp_size < i)
335         return NULL;
336 
337     /*
338      * Set up the indexing for the specified row...
339      */
340 #if defined (WIN32) || defined (cygwin) || defined(openbsd5)
341     port = ntohl((u_long)udp_head[i].UDPTABLE_LOCALADDRESS);
342     snmp_set_var_value(index, (u_char *)&port,
343                                   sizeof(udp_head[i].UDPTABLE_LOCALADDRESS));
344 #else
345     snmp_set_var_value(index, (u_char *)&udp_head[i].UDPTABLE_LOCALADDRESS,
346                                   sizeof(udp_head[i].UDPTABLE_LOCALADDRESS));
347 #endif
348     port = UDP_PORT_TO_HOST_ORDER((u_short)udp_head[i].UDPTABLE_LOCALPORT);
349     snmp_set_var_value(index->next_variable,
350                                (u_char*)&port, sizeof(port));
351     /*
352      * ... return the data structure for this row,
353      * and update the loop context ready for the next one.
354      */
355     *data_context = (void*)&udp_head[i];
356     *loop_context = (void*)(intptr_t)++i;
357     return index;
358 }
359 
360 void
udpTable_free(netsnmp_cache * cache,void * magic)361 udpTable_free(netsnmp_cache *cache, void *magic)
362 {
363 #if defined (WIN32) || defined (cygwin)
364     if (udp_head) {
365 		/* the allocated structure is a count followed by table entries */
366 		free((char *)(udp_head) - sizeof(DWORD));
367 	}
368 #elif defined(openbsd5)
369 #else
370     if (udp_head)
371         free(udp_head);
372 #endif
373     udp_head = NULL;
374     udp_size = 0;
375 }
376 #else
377 #ifdef UDPTABLE_IS_LINKED_LIST
378 netsnmp_variable_list *
udpTable_first_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)379 udpTable_first_entry(void **loop_context,
380                      void **data_context,
381                      netsnmp_variable_list *index,
382                      netsnmp_iterator_info *data)
383 {
384     /*
385      * XXX - How can we tell if the cache is valid?
386      *       No access to 'reqinfo'
387      */
388     if (udp_head == NULL)
389         return NULL;
390 
391     /*
392      * Point to the first entry, and use the
393      * 'next_entry' hook to retrieve this row
394      */
395     *loop_context = (void*)udp_head;
396     return udpTable_next_entry( loop_context, data_context, index, data );
397 }
398 
399 netsnmp_variable_list *
udpTable_next_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)400 udpTable_next_entry( void **loop_context,
401                      void **data_context,
402                      netsnmp_variable_list *index,
403                      netsnmp_iterator_info *data)
404 {
405     UDPTABLE_ENTRY_TYPE	 *entry = (UDPTABLE_ENTRY_TYPE *)*loop_context;
406     long port;
407     in_addr_t addr;
408 
409     if (!entry)
410         return NULL;
411 
412     /*
413      * Set up the indexing for the specified row...
414      */
415 #if defined(osf5) && defined(IN6_EXTRACT_V4ADDR)
416                 snmp_set_var_value(index,
417                               (u_char*)&IN6_EXTRACT_V4ADDR(&entry->pcb.inp_laddr),
418                                  sizeof(IN6_EXTRACT_V4ADDR(&entry->pcb.inp_laddr)));
419 #else
420     addr = UDP_ADDRESS_TO_NETWORK_ORDER((in_addr_t)entry->UDPTABLE_LOCALADDRESS);
421     snmp_set_var_value(index, (u_char *)&addr,
422                                  sizeof(addr));
423 #endif
424     port = UDP_PORT_TO_HOST_ORDER(entry->UDPTABLE_LOCALPORT);
425     snmp_set_var_value(index->next_variable,
426                                (u_char*)&port, sizeof(port));
427 
428     /*
429      * ... return the data structure for this row,
430      * and update the loop context ready for the next one.
431      */
432     *data_context = (void*)entry;
433     *loop_context = (void*)entry->INP_NEXT_SYMBOL;
434     return index;
435 }
436 
437 void
udpTable_free(netsnmp_cache * cache,void * magic)438 udpTable_free(netsnmp_cache *cache, void *magic)
439 {
440     UDPTABLE_ENTRY_TYPE	 *p;
441     while (udp_head) {
442         p = udp_head;
443         udp_head = udp_head->INP_NEXT_SYMBOL;
444         free(p);
445     }
446 
447     udp_head = NULL;
448 }
449 #endif		/* UDPTABLE_IS_LINKED_LIST */
450 #endif		/* UDPTABLE_IS_TABLE */
451 
452 
453 	/*
454 	 *
455 	 * The cache-handler loading routine is the main
456 	 *    place for architecture-specific code
457 	 *
458 	 * Load into either a table structure, or a linked list
459 	 *    depending on the system architecture
460 	 */
461 
462 
463 #ifdef hpux11
464 int
udpTable_load(netsnmp_cache * cache,void * vmagic)465 udpTable_load(netsnmp_cache *cache, void *vmagic)
466 {
467     int             fd;
468     struct nmparms  p;
469     int             val = 0;
470     unsigned int    ulen;
471     int             ret;
472 
473     udpTable_free(NULL, NULL);
474 
475     if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
476         p.objid = ID_udpLsnNumEnt;
477         p.buffer = (void *) &val;
478         ulen = sizeof(int);
479         p.len = &ulen;
480         if ((ret = get_mib_info(fd, &p)) == 0)
481             udp_size = val;
482 
483         if (udp_size > 0) {
484             ulen = (unsigned) udp_size *sizeof(mib_udpLsnEnt);
485             udp_head = (mib_udpLsnEnt *) malloc(ulen);
486             p.objid = ID_udpLsnTable;
487             p.buffer = (void *) udp_head;
488             p.len = &ulen;
489             if ((ret = get_mib_info(fd, &p)) < 0) {
490                 udp_size = 0;
491             }
492         }
493 
494         close_mib(fd);
495     }
496 
497     if (udp_size > 0) {
498         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (hpux11)\n"));
499         return 0;
500     }
501     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (hpux11)\n"));
502     return -1;
503 }
504 
505 #elif defined(linux)
506 int
udpTable_load(netsnmp_cache * cache,void * vmagic)507 udpTable_load(netsnmp_cache *cache, void *vmagic)
508 {
509     FILE           *in;
510     char            line[256];
511 
512     udpTable_free(cache, NULL);
513 
514     if (!(in = fopen("/proc/net/udp", "r"))) {
515         DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (linux)\n"));
516         NETSNMP_LOGONCE((LOG_ERR, "snmpd: cannot open /proc/net/udp ...\n"));
517         return -1;
518     }
519 
520     /*
521      * scan proc-file and build up a linked list
522      * This will actually be built up in reverse,
523      *   but since the entries are unsorted, that doesn't matter.
524      */
525     while (line == fgets(line, sizeof(line), in)) {
526         struct inpcb    pcb, *nnew;
527         unsigned int    state, lport;
528 
529         memset(&pcb, 0, sizeof(pcb));
530 
531         if (3 != sscanf(line, "%*d: %x:%x %*x:%*x %x",
532                         &pcb.inp_laddr.s_addr, &lport, &state))
533             continue;
534 
535         if (state != 7)         /* fix me:  UDP_LISTEN ??? */
536             continue;
537 
538         /* store in network byte order */
539         pcb.inp_laddr.s_addr = htonl(pcb.inp_laddr.s_addr);
540         pcb.inp_lport = htons((unsigned short) (lport));
541 
542         nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
543         if (nnew == NULL)
544             break;
545         memcpy(nnew, &pcb, sizeof(struct inpcb));
546         nnew->inp_next = udp_head;
547         udp_head       = nnew;
548     }
549 
550     fclose(in);
551 
552     DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (linux)\n"));
553     return 0;
554 }
555 
556 #elif HAVE_KVM_GETFILES
557 
558 int
udpTable_load(netsnmp_cache * cache,void * vmagic)559 udpTable_load(netsnmp_cache *cache, void *vmagic)
560 {
561     int count;
562     udp_head = kvm_getfiles(kd, KERN_FILE_BYFILE, DTYPE_SOCKET, sizeof(struct kinfo_file), &count);
563     udp_size = count;
564     DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (kvm_getfiles)\n"));
565     return 0;
566 }
567 
568 #elif defined(solaris2)
569 static int
UDP_Cmp(void * addr,void * ep)570 UDP_Cmp(void *addr, void *ep)
571 {
572     if (memcmp((mib2_udpEntry_t *) ep, (mib2_udpEntry_t *) addr,
573                sizeof(mib2_udpEntry_t)) == 0)
574         return (0);
575     else
576         return (1);
577 }
578 
579 
580 int
udpTable_load(netsnmp_cache * cache,void * vmagic)581 udpTable_load(netsnmp_cache *cache, void *vmagic)
582 {
583     mib2_udpEntry_t   entry;
584     netsnmp_udpEntry *nnew;
585     netsnmp_udpEntry *prev_entry = NULL;
586 
587 
588     udpTable_free(NULL, NULL);
589 
590     if (getMibstat(MIB_UDP_LISTEN, &entry, sizeof(mib2_udpEntry_t),
591                    GET_FIRST, &UDP_Cmp, &entry) != 0) {
592         DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (solaris)\n"));
593         return -1;
594     }
595 
596     while (1) {
597         /*
598          * Not interested in 'idle' entries, apparently....
599          */
600         DEBUGMSGTL(("mibII/udpTable", "UDP Entry %x:%d (%d)\n",
601                      entry.udpLocalAddress, entry.udpLocalPort, entry.udpEntryInfo.ue_state));
602         if (entry.udpEntryInfo.ue_state == MIB2_UDP_idle) {
603             /*
604              * Build up a linked list copy of the getMibstat results
605              * Note that since getMibstat returns rows in sorted order,
606 	     *    we need to retain this order while building the list
607 	     *    so new entries are added onto the end of the list.
608              * xxx-rks: WARNING: this is NOT TRUE on the sf cf solaris boxes.
609              */
610             nnew = SNMP_MALLOC_TYPEDEF(netsnmp_udpEntry);
611             if (nnew == NULL)
612                 break;
613             memcpy(&(nnew->entry), &entry, sizeof(mib2_udpEntry_t));
614             if (!prev_entry)
615 	        udp_head = nnew;
616 	    else
617 	        prev_entry->inp_next = nnew;
618 	    prev_entry = nnew;
619 	}
620 
621         if (getMibstat(MIB_UDP_LISTEN, &entry, sizeof(mib2_udpEntry_t),
622                        GET_NEXT, &UDP_Cmp, &entry) != 0)
623 	    break;
624     }
625 
626     if (udp_head) {
627         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (solaris)\n"));
628         return 0;
629     }
630     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (solaris)\n"));
631     return -1;
632 }
633 
634 #elif defined (WIN32) || defined (cygwin)
635 int
udpTable_load(netsnmp_cache * cache,void * vmagic)636 udpTable_load(netsnmp_cache *cache, void *vmagic)
637 {
638     PMIB_UDPTABLE pUdpTable = NULL;
639     DWORD         dwActualSize = 0;
640     DWORD         status = NO_ERROR;
641 
642     /*
643      * query for the buffer size needed
644      */
645     status = GetUdpTable(pUdpTable, &dwActualSize, TRUE);
646     if (status == ERROR_INSUFFICIENT_BUFFER) {
647         pUdpTable = (PMIB_UDPTABLE) malloc(dwActualSize);
648         if (pUdpTable != NULL) {
649             /*
650              * Get the sorted UDP table
651              */
652             status = GetUdpTable(pUdpTable, &dwActualSize, TRUE);
653         }
654     }
655     if (status == NO_ERROR) {
656         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (win32)\n"));
657         udp_size = pUdpTable->dwNumEntries -1;  /* entries are counted starting with 0 */
658         udp_head = pUdpTable->table;
659         return 0;
660     }
661     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (win32)\n"));
662     if (pUdpTable)
663 	free(pUdpTable);
664     return -1;
665 }
666 
667 #elif (defined(NETSNMP_CAN_USE_SYSCTL) && defined(UDPCTL_PCBLIST))
668 int
udpTable_load(netsnmp_cache * cache,void * vmagic)669 udpTable_load(netsnmp_cache *cache, void *vmagic)
670 {
671     size_t   len;
672     int      sname[] = { CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_PCBLIST };
673     char     *udpcb_buf = NULL;
674 #if defined(dragonfly)
675     struct xinpcb  *xig = NULL;
676 #else
677     struct xinpgen *xig = NULL;
678 #endif
679     UDPTABLE_ENTRY_TYPE  *nnew;
680 
681     udpTable_free(NULL, NULL);
682 
683     /*
684      *  Read in the buffer containing the UDP table data
685      */
686     len = 0;
687     if (sysctl(sname, 4, 0, &len, 0, 0) < 0 ||
688        (udpcb_buf = malloc(len)) == NULL)
689         return -1;
690     if (sysctl(sname, 4, udpcb_buf, &len, 0, 0) < 0) {
691         free(udpcb_buf);
692         return -1;
693     }
694 
695     /*
696      *  Unpick this into the constituent 'xinpgen' structures, and extract
697      *     the 'inpcb' elements into a linked list (built in reverse)
698      */
699 #if defined(dragonfly)
700     xig = (struct xinpcb  *) udpcb_buf;
701 #else
702     xig = (struct xinpgen *) udpcb_buf;
703     xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
704 #endif
705 
706 #if defined(dragonfly)
707     while (xig && ((char *)xig + xig->xi_len < udpcb_buf + len))
708 #else
709     while (xig && (xig->xig_len > sizeof(struct xinpgen)))
710 #endif
711     {
712         nnew = SNMP_MALLOC_TYPEDEF(UDPTABLE_ENTRY_TYPE);
713         if (!nnew)
714             break;
715 #if __FreeBSD_version >= 1200026
716         memcpy(&nnew->pcb, xig, sizeof(struct xinpcb));
717 #else
718         memcpy(&nnew->pcb, &((struct xinpcb *) xig)->xi_inp, sizeof(struct inpcb));
719 #endif
720 	nnew->inp_next = udp_head;
721 	udp_head   = nnew;
722 #if defined(dragonfly)
723         xig = (struct xinpcb  *) ((char *) xig + xig->xi_len);
724 #else
725         xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
726 #endif
727     }
728 
729     free(udpcb_buf);
730     if (udp_head) {
731         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (sysctl)\n"));
732         return 0;
733     }
734     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (sysctl)\n"));
735     return -1;
736 }
737 
738 #elif defined(PCB_TABLE)
739 int
udpTable_load(netsnmp_cache * cache,void * vmagic)740 udpTable_load(netsnmp_cache *cache, void *vmagic)
741 {
742     struct inpcbtable table;
743     struct inpcb   *nnew, *entry;
744 
745     udpTable_free(NULL, NULL);
746 
747     if (!auto_nlist(UDB_SYMBOL, (char *) &table, sizeof(table))) {
748         DEBUGMSGTL(("mibII/udpTable", "Failed to read inpcbtable\n"));
749         return -1;
750     }
751 
752     /*
753      *  Set up a linked list
754      */
755     entry  = table.INP_FIRST_SYMBOL;
756     while (entry) {
757 
758         nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
759         if (!nnew)
760             break;
761 
762         if (!NETSNMP_KLOOKUP(entry, (char *) nnew, sizeof(struct inpcb))) {
763             DEBUGMSGTL(("mibII/udpTable:udpTable_load", "klookup failed\n"));
764             break;
765         }
766 
767         entry    = nnew->INP_NEXT_SYMBOL;	/* Next kernel entry */
768 	nnew->INP_NEXT_SYMBOL = udp_head;
769 	udp_head = nnew;
770 
771         if (entry == table.INP_FIRST_SYMBOL)
772             break;
773     }
774 
775     if (udp_head) {
776         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (pcb_table)\n"));
777         return 0;
778     }
779     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (pcb_table)\n"));
780     return -1;
781 }
782 
783 #elif defined(UDB_SYMBOL)
784 int
udpTable_load(netsnmp_cache * cache,void * vmagic)785 udpTable_load(netsnmp_cache *cache, void *vmagic)
786 {
787     struct inpcb   udp_inpcb;
788     struct inpcb   *nnew, *entry;
789 
790     udpTable_free(NULL, NULL);
791 
792     if (!auto_nlist(UDB_SYMBOL, (char *) &udp_inpcb, sizeof(udp_inpcb))) {
793         DEBUGMSGTL(("mibII/udpTable", "Failed to read udb_symbol\n"));
794         return -1;
795     }
796 
797     /*
798      *  Set up a linked list
799      */
800     entry  = udp_inpcb.INP_NEXT_SYMBOL;
801     while (entry) {
802 
803         nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
804         if (!nnew)
805             break;
806 
807         if (!NETSNMP_KLOOKUP(entry, (char *) nnew, sizeof(struct inpcb))) {
808             DEBUGMSGTL(("mibII/udpTable:udpTable_load", "klookup failed\n"));
809             break;
810         }
811 
812         entry    = nnew->INP_NEXT_SYMBOL;		/* Next kernel entry */
813 	nnew->INP_NEXT_SYMBOL = udp_head;
814 	udp_head = nnew;
815 
816         if (entry == udp_inpcb.INP_NEXT_SYMBOL)
817             break;
818     }
819 
820     if (udp_head) {
821         DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table (udb_symbol)\n"));
822         return 0;
823     }
824     DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (udb_symbol)\n"));
825     return -1;
826 }
827 
828 #else				/* UDB_SYMBOL */
829 int
udpTable_load(netsnmp_cache * cache,void * vmagic)830 udpTable_load(netsnmp_cache *cache, void *vmagic)
831 {
832     DEBUGMSGTL(("mibII/udpTable", "Loading UDP Table not implemented\n"));
833     return -1;
834 }
835 #endif				/* UDB_SYMBOL */
836