-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsnmp.c
154 lines (130 loc) · 3.96 KB
/
snmp.c
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
145
146
147
148
149
150
151
152
153
/*
* Part of `snmp-query-engine`.
*
* Copyright 2012-2014, Anton Berezin <[email protected]>
* Modified BSD license.
* (See LICENSE file in the distribution.)
*
*/
#include "sqe.h"
static struct socket_info *snmp = NULL;
static void
snmp_process_datagram(struct socket_info *snmp, struct sockaddr_in *from, char *buf, int n)
{
struct ber enc, *e;
unsigned char t;
unsigned l;
unsigned sid;
char *trace;
struct destination *dest;
struct sid_info *si;
PS.octets_received += n;
dest = find_destination(&from->sin_addr, ntohs(from->sin_port));
if (!dest) {
fprintf(stderr, "destination %s:%d is not knowing, ignoring packet\n", inet_ntoa(from->sin_addr), ntohs(from->sin_port));
return;
}
dest->octets_received += n;
dest->packets_on_the_wire--;
if (dest->packets_on_the_wire < 0)
dest->packets_on_the_wire = 0;
PS.packets_on_the_wire--;
if (PS.packets_on_the_wire < 0)
PS.packets_on_the_wire = 0;
// fprintf(stderr, "%s: snmp_receive->(%d)\n", inet_ntoa(dest->ip), dest->packets_on_the_wire);
enc = ber_init(buf, n); e = &enc;
#define CHECK(prob, val) if ((val) < 0) { trace = "decoding" # prob; goto bad_snmp_packet; }
CHECK("start sequence", decode_sequence(e, NULL));
CHECK("version", decode_integer(e, -1, NULL));
trace = "community type/len";
if (decode_type_len(e, &t, &l) < 0) goto bad_snmp_packet;
trace = "community type";
if (t != AT_STRING) goto bad_snmp_packet;
e->b += l; e->len += l; // XXX skip community
CHECK("PDU", decode_composite(e, PDU_GET_RESPONSE, NULL));
CHECK("decoding request id", decode_integer(e, -1, &sid));
#undef CHECK
si = find_sid_info(dest, sid);
if (!si) {
fprintf(stderr, "unable to find sid_info with sid %u, ignoring packet\n", sid);
return;
}
// fprintf(stderr, "this packet appears to be legit, sid %u(%u)\n", sid, si->sid);
if (process_sid_info_response(si, e))
free_sid_info(si);
maybe_query_destination(dest);
return;
bad_snmp_packet:
PS.bad_snmp_responses++;
fprintf(stderr, "bad SNMP packet, ignoring: %s\n", trace);
maybe_query_destination(dest);
}
static void
snmp_receive(struct socket_info *snmp)
{
struct sockaddr_in from;
socklen_t len;
char buf[65000];
int n;
while (1) {
len = sizeof(from);
if ( (n = recvfrom(snmp->fd, buf, 65000, 0, (struct sockaddr *)&from, &len)) < 0) {
if (errno == EAGAIN)
return;
croak(1, "snmp_receive: recvfrom");
}
snmp_process_datagram(snmp, &from, buf, n);
}
}
void
create_snmp_socket(void)
{
int fd;
int n;
int flags;
if (snmp)
croakx(1, "create_snmp_socket: socket already exists");
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0)
croak(1, "create_snmp_socket: socket");
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
croak(1, "create_snmp_socket: fcntl(getfl)");
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
croak(1, "create_snmp_socket: fcntl(setfl)");
/* try a very large receive buffer size */
n = 100 * 1024 * 1024;
while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) < 0)
n /= 2;
PS.udp_receive_buffer_size = n;
/* additionally, try a very large send buffer size :) */
n = 100 * 1024 * 1024;
while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) < 0)
n /= 2;
PS.udp_send_buffer_size = n;
snmp = new_socket_info(fd);
on_read(snmp, snmp_receive);
}
void snmp_send(struct destination *dest, struct ber *packet)
{
destination_start_timing(dest);
dest->packets_on_the_wire++;
PS.packets_on_the_wire++;
//fprintf(stderr, "%s: snmp_send->(%d)\n", inet_ntoa(dest->ip), dest->packets_on_the_wire);
if (sendto(snmp->fd, packet->buf, packet->len, 0,
(struct sockaddr *)&dest->dest_addr,
sizeof(dest->dest_addr))
!= packet->len)
{
if (errno == EAGAIN) {
PS.udp_send_buffer_overflow++;
return;
}
croak(1, "snmp_send: sendto");
}
//fprintf(stderr, "UDP datagram of %d bytes sent to %s:%d\n", packet->len, inet_ntoa(dest->dest_addr.sin_addr), ntohs(dest->dest_addr.sin_port));
//dump_buf(stderr, packet->buf, packet->len);
dest->octets_sent += packet->len;
PS.octets_sent += packet->len;
}