-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnetsnmp_patch.diff
144 lines (134 loc) · 6.05 KB
/
netsnmp_patch.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
diff --git a/src/include/net-snmp/library/snmp_api.h b/src/include/net-snmp/library/snmp_api.h
index 6f658d5..5587715 100644
--- a/src/include/net-snmp/library/snmp_api.h
+++ b/src/include/net-snmp/library/snmp_api.h
@@ -160,6 +160,7 @@ typedef struct request_list {
#define SNMP_DETAIL_SIZE 512
+#define SNMP_FLAGS_AX_ASYNC_SELECT 0x200000 /* Indicates that myvoid has an async select. */
#define SNMP_FLAGS_UDP_BROADCAST 0x800
#define SNMP_FLAGS_RESP_CALLBACK 0x400 /* Additional callback on response */
#define SNMP_FLAGS_USER_CREATED 0x200 /* USM user has been created */
diff --git a/src/include/net-snmp/library/snmp_transport.h b/src/include/net-snmp/library/snmp_transport.h
index 4162897..f3cdb0b 100644
--- a/src/include/net-snmp/library/snmp_transport.h
+++ b/src/include/net-snmp/library/snmp_transport.h
@@ -50,6 +50,34 @@ extern "C" {
#define NETSNMP_TRANSPORT_FLAG_OPENED 0x20 /* f_open called */
#define NETSNMP_TRANSPORT_FLAG_HOSTNAME 0x80 /* for fmtaddr hook */
+/* I know this is wired shit.
+ * The root cause for this: fd_set only supports 1024 sockets.
+ * To understand why this causes trouble here is bit more backround:
+ * As you know a socket is just a number (file descriptor),
+ * so when you request a socket from the kernel you get just a number back.
+ * The problem with fd_set is, it's only a bitmap. Which means for socket
+ * number 30, the bit 30 is set. For socket number 700, bit 700 is set.
+ * .... and so on.
+ * As written above fd_set only support 1024 sockets, which means the bitmap
+ * supports only sockets till number 1024.
+ * Well, what happens now if we have a socket with number 2000.
+ * (2000 sockets is nothing abnormal for a high concurrent snmp collector).
+ * Inside snmp_api.c the following would happen: FD_SET(fdset, 2000)
+ * FD_SET is pretty stupid and just sets the bit 2000 starting from fdset.
+ * However fdset is only 1024 bits big, => FD_SET(fdset, 2000) sets bits in a
+ * memory region its not allowed to. Flipping bits in random memory regions
+ * leads to SEGFAULT.
+ *
+ * When we use gevent_snmp this fdset is NOT needed at all => the problematic
+ * calls FD_SET, FD_ISSET, FD_CLR are not required.
+ * This is what the SNMP_FLAGS_AX_IGNORE_FDSET should trigger. Its set on the
+ * session->flags and can be tested everywhere in the code.
+ *
+ * In snmplib 5.7 they invented a 'large_fdset', which leads to segfaults.
+ * So even for jessi it is needed as well.
+ */
+#define NETSNMP_TRANSPORT_FLAG_AX_IGNORE_FDSET 0x100000
+
/* The standard SNMP domains. */
NETSNMP_IMPORT oid netsnmpUDPDomain[]; /* = { 1, 3, 6, 1, 6, 1, 1 }; */
diff --git a/src/snmplib/snmp_api.c b/src/snmplib/snmp_api.c
index 1823e0c..2998e39 100644
--- a/src/snmplib/snmp_api.c
+++ b/src/snmplib/snmp_api.c
@@ -343,7 +343,7 @@ static int snmp_detail_f = 0;
int snmp_build(u_char ** pkt, size_t * pkt_len,
size_t * offset, netsnmp_session * pss,
netsnmp_pdu *pdu);
-static int snmp_parse(void *, netsnmp_session *, netsnmp_pdu *,
+int snmp_parse(void *, netsnmp_session *, netsnmp_pdu *,
u_char *, size_t);
static void snmpv3_calc_msg_flags(int, int, u_char *);
@@ -4321,7 +4321,7 @@ _snmp_parse(void *sessp,
return result;
}
-static int
+int
snmp_parse(void *sessp,
netsnmp_session * pss,
netsnmp_pdu *pdu, u_char * data, size_t length)
@@ -5508,12 +5508,14 @@ _sess_read(void *sessp, netsnmp_large_fd_set * fdset)
return 0;
}
- if (!fdset || !(NETSNMP_LARGE_FD_ISSET(transport->sock, fdset))) {
- DEBUGMSGTL(("sess_read", "not reading %d (fdset %p set %d)\n",
- transport->sock, fdset,
- fdset ? NETSNMP_LARGE_FD_ISSET(transport->sock, fdset)
- : -9));
- return 0;
+ if (!(transport->flags & NETSNMP_TRANSPORT_FLAG_AX_IGNORE_FDSET)) {
+ if (!fdset || !(NETSNMP_LARGE_FD_ISSET(transport->sock, fdset))) {
+ DEBUGMSGTL(("sess_read", "not reading %d (fdset %p set %d)\n",
+ transport->sock, fdset,
+ fdset ? NETSNMP_LARGE_FD_ISSET(transport->sock, fdset)
+ : -9));
+ return 0;
+ }
}
sp->s_snmp_errno = 0;
@@ -6048,7 +6050,10 @@ snmp_sess_select_info2_flags(void *sessp, int *numfds,
*numfds = (slp->transport->sock + 1);
}
- NETSNMP_LARGE_FD_SET(slp->transport->sock, fdset);
+ if (!(slp->transport->flags & NETSNMP_TRANSPORT_FLAG_AX_IGNORE_FDSET)) {
+ NETSNMP_LARGE_FD_SET(slp->transport->sock, fdset);
+ }
+
if (slp->internal != NULL && slp->internal->requests) {
/*
* Found another session with outstanding requests.
diff --git a/src/snmplib/snmp_client.c b/src/snmplib/snmp_client.c
index c1aa9c4..d7a6261 100644
--- a/src/snmplib/snmp_client.c
+++ b/src/snmplib/snmp_client.c
@@ -1111,6 +1111,17 @@ snmp_synch_response(netsnmp_session * ss,
return snmp_synch_response_cb(ss, pdu, response, snmp_synch_input);
}
+typedef int (*ax_select_func) (void* ctx, struct timeval* timeout);
+
+typedef struct {
+ ax_select_func func;
+ void* ctx;
+} ax_async_ctx_t;
+
+#define GET_AX_ASYNC_FUNC(ss) (((ax_async_ctx_t*)(ss->myvoid))->func)
+#define GET_AX_ASYNC_CTX(ss) (((ax_async_ctx_t*)(ss->myvoid))->ctx)
+
+
int
snmp_sess_synch_response(void *sessp,
netsnmp_pdu *pdu, netsnmp_pdu **response)
@@ -1152,7 +1163,14 @@ snmp_sess_synch_response(void *sessp,
NETSNMP_SELECT_NOALARMS);
if (block == 1)
tvp = NULL; /* block without timeout */
- count = select(numfds, &fdset, NULL, NULL, tvp);
+
+ if ((ss->myvoid != NULL) && (ss->flags & SNMP_FLAGS_AX_ASYNC_SELECT)) {
+ count = GET_AX_ASYNC_FUNC(ss)(GET_AX_ASYNC_CTX(ss), tvp);
+ }
+ else {
+ count = select(numfds, &fdset, NULL, NULL, tvp);
+ }
+
if (count > 0) {
snmp_sess_read(sessp, &fdset);
} else