1#include "ipf.h"
2#include "netinet/ipl.h"
3#include "ipmon.h"
4#include <ctype.h>
5
6static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 };
7/*
8 * Enterprise number OID:
9 * 1.3.6.1.4.1.9932
10 */
11static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
12static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
13
14static int writeint(u_char *, int);
15static int writelength(u_char *, u_int);
16static int maketrap_v2(char *, u_char *, int, u_char *, int);
17static void snmpv2_destroy(void *);
18static void *snmpv2_dup(void *);
19static int snmpv2_match(void *, void *);
20static void *snmpv2_parse(char **);
21static void snmpv2_print(void *);
22static int snmpv2_send(void *, ipmon_msg_t *);
23
24
25int sendtrap_v2_0(int, char *, char *, int);
26
27static char def_community[] = "public";	/* ublic */
28
29typedef struct snmpv2_opts_s {
30	char			*community;
31	char			*server;
32	int			fd;
33	int			v6;
34	int			ref;
35#ifdef USE_INET6
36	struct sockaddr_in6	sin6;
37#endif
38	struct sockaddr_in	sin;
39} snmpv2_opts_t;
40
41ipmon_saver_t snmpv2saver = {
42	"snmpv2",
43	snmpv2_destroy,
44	snmpv2_dup,		/* dup */
45	snmpv2_match,		/* match */
46	snmpv2_parse,
47	snmpv2_print,
48	snmpv2_send
49};
50
51
52static int
53snmpv2_match(ctx1, ctx2)
54	void *ctx1, *ctx2;
55{
56	snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
57
58	if (s1->v6 != s2->v6)
59		return 1;
60
61	if (strcmp(s1->community, s2->community))
62		return 1;
63
64#ifdef USE_INET6
65	if (s1->v6 == 1) {
66		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
67			return 1;
68	} else
69#endif
70	{
71		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
72			return 1;
73	}
74
75	return 0;
76}
77
78
79static void *
80snmpv2_dup(ctx)
81	void *ctx;
82{
83	snmpv2_opts_t *s = ctx;
84
85	s->ref++;
86	return s;
87}
88
89
90static void
91snmpv2_print(ctx)
92        void *ctx;
93{
94	snmpv2_opts_t *snmpv2 = ctx;
95
96	printf("%s ", snmpv2->community);
97#ifdef USE_INET6
98	if (snmpv2->v6 == 1) {
99		char buf[80];
100
101		printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
102				       sizeof(snmpv2->sin6.sin6_addr)));
103	} else
104#endif
105	{
106		printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
107	}
108}
109
110
111static void *
112snmpv2_parse(char **strings)
113{
114	snmpv2_opts_t *ctx;
115	int result;
116	char *str;
117	char *s;
118
119	if (strings[0] == NULL || strings[0][0] == '\0')
120		return NULL;
121	if (strchr(*strings, ' ') == NULL)
122		return NULL;
123
124	str = strdup(*strings);
125
126	ctx = calloc(1, sizeof(*ctx));
127	if (ctx == NULL) {
128		free(str);
129		return NULL;
130	}
131
132	ctx->fd = -1;
133
134	s = strchr(str, ' ');
135	*s++ = '\0';
136	ctx->community = str;
137
138	while (ISSPACE(*s))
139		s++;
140	if (!*s) {
141		free(str);
142		free(ctx);
143		return NULL;
144	}
145
146#ifdef USE_INET6
147	if (strchr(s, ':') == NULL) {
148		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
149		if (result == 1) {
150			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
151			if (ctx->fd >= 0) {
152				ctx->sin.sin_family = AF_INET;
153				ctx->sin.sin_port = htons(162);
154				if (connect(ctx->fd,
155					    (struct sockaddr *)&ctx->sin,
156					    sizeof(ctx->sin)) != 0) {
157						snmpv2_destroy(ctx);
158						return NULL;
159				}
160			}
161		}
162	} else {
163		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
164		if (result == 1) {
165			ctx->v6 = 1;
166			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
167			if (ctx->fd >= 0) {
168				ctx->sin6.sin6_family = AF_INET6;
169				ctx->sin6.sin6_port = htons(162);
170				if (connect(ctx->fd,
171					    (struct sockaddr *)&ctx->sin6,
172					    sizeof(ctx->sin6)) != 0) {
173						snmpv2_destroy(ctx);
174						return NULL;
175				}
176			}
177		}
178	}
179#else
180	result = inet_aton(s, &ctx->sin.sin_addr);
181	if (result == 1) {
182		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
183		if (ctx->fd >= 0) {
184			ctx->sin.sin_family = AF_INET;
185			ctx->sin.sin_port = htons(162);
186			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
187				    sizeof(ctx->sin)) != 0) {
188					snmpv2_destroy(ctx);
189					return NULL;
190			}
191		}
192	}
193#endif
194
195	if (result != 1) {
196		free(str);
197		free(ctx);
198		return NULL;
199	}
200
201	ctx->ref = 1;
202
203	return ctx;
204}
205
206
207static void
208snmpv2_destroy(ctx)
209	void *ctx;
210{
211	snmpv2_opts_t *v2 = ctx;
212
213	v2->ref--;
214	if (v2->ref > 0)
215		return;
216
217	if (v2->community)
218		free(v2->community);
219	if (v2->fd >= 0)
220		close(v2->fd);
221	free(v2);
222}
223
224
225static int
226snmpv2_send(ctx, msg)
227	void *ctx;
228	ipmon_msg_t *msg;
229{
230	snmpv2_opts_t *v2 = ctx;
231
232	return sendtrap_v2_0(v2->fd, v2->community,
233			     msg->imm_msg, msg->imm_msglen);
234}
235static int
236writelength(buffer, value)
237	u_char *buffer;
238	u_int value;
239{
240	u_int n = htonl(value);
241	int len;
242
243	if (value < 128) {
244		*buffer = value;
245		return 1;
246	}
247	if (value > 0xffffff)
248		len = 4;
249	else if (value > 0xffff)
250		len = 3;
251	else if (value > 0xff)
252		len = 2;
253	else
254		len = 1;
255
256	*buffer = 0x80 | len;
257
258	bcopy((u_char *)&n + 4 - len, buffer + 1, len);
259
260	return len + 1;
261}
262
263
264static int
265writeint(buffer, value)
266	u_char *buffer;
267	int value;
268{
269	u_char *s = buffer;
270	u_int n = value;
271
272	if (value == 0) {
273		*buffer = 0;
274		return 1;
275	}
276
277	if (n >  4194304) {
278		*s++ = 0x80 | (n / 4194304);
279		n -= 4194304 * (n / 4194304);
280	}
281	if (n >  32768) {
282		*s++ = 0x80 | (n / 32768);
283		n -= 32768 * (n / 327678);
284	}
285	if (n > 128) {
286		*s++ = 0x80 | (n / 128);
287		n -= (n / 128) * 128;
288	}
289	*s++ = (u_char)n;
290
291	return s - buffer;
292}
293
294
295
296/*
297 * First style of traps is:
298 * 1.3.6.1.4.1.9932.1.1
299 */
300static int
301maketrap_v2(community, buffer, bufsize, msg, msglen)
302	char *community;
303	u_char *buffer;
304	int bufsize;
305	u_char *msg;
306	int msglen;
307{
308	u_char *s = buffer, *t, *pdulen;
309	u_char *varlen;
310	int basesize = 77;
311	u_short len;
312	int trapmsglen;
313	int pdulensz;
314	int varlensz;
315	int baselensz;
316	int n;
317
318	if (community == NULL || *community == '\0')
319		community = def_community;
320	basesize += strlen(community) + msglen;
321
322	if (basesize + 8 > bufsize)
323		return 0;
324
325	memset(buffer, 0xff, bufsize);
326	*s++ = 0x30;		/* Sequence */
327
328	if (basesize - 1 >= 128) {
329		baselensz = 2;
330		basesize++;
331	} else {
332		baselensz = 1;
333	}
334	s += baselensz;
335	*s++ = 0x02;		/* Integer32 */
336	*s++ = 0x01;		/* length 1 */
337	*s++ = 0x01;		/* version 2 */
338	*s++ = 0x04;		/* octet string */
339	*s++ = strlen(community);		/* length of "public" */
340	bcopy(community, s, s[-1]);
341	s += s[-1];
342	*s++ = 0xA7;		/* PDU(7) */
343	pdulen = s++;
344	if (basesize - (s - buffer) >= 128) {
345		pdulensz = 2;
346		basesize++;
347		s++;
348	} else {
349		pdulensz = 1;
350	}
351	/* request id */
352	*s++ = 0x2;	/* integer */
353	*s++ = 0x4;	/* len 4 */
354	*s++ = 0x0;	/* noError */
355	*s++ = 0x0;	/* noError */
356	*s++ = 0x0;	/* noError */
357	*s++ = 0x0;	/* noError */
358
359	/* error status */
360	*s++ = 0x2;	/* integer */
361	*s++ = 0x1;	/* len 1 */
362	*s++ = 0x0;	/* noError */
363
364	/* error-index */
365	*s++ = 0x2;	/* integer */
366	*s++ = 0x1;	/* len 1 */
367	*s++ = 0x0;	/* noError */
368
369	*s++ = 0x30;	/* sequence */
370	varlen = s++;
371	if (basesize - (s - buffer) >= 128) {
372		varlensz = 2;
373		basesize++;
374		s++;
375	} else {
376		varlensz = 1;
377	}
378
379	*s++ = 0x30;	/* sequence */
380	*s++ = sizeof(sysuptime) + 6;
381
382	bcopy(sysuptime, s, sizeof(sysuptime));
383	s += sizeof(sysuptime);
384
385	*s++ = 0x43;	/* Timestamp */
386	*s++ = 0x04;	/* TimeTicks */
387	*s++ = 0x0;
388	*s++ = 0x0;
389	*s++ = 0x0;
390	*s++ = 0x0;
391
392	*s++ = 0x30;
393	t = s + 1;
394	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
395	t += sizeof(ipf_trap0_1);
396
397	*t++ = 0x2;		/* Integer */
398	n = writeint(t + 1, IPFILTER_VERSION);
399	*t = n;
400	t += n + 1;
401
402	len = t - s - 1;
403	writelength(s, len);
404
405	s = t;
406	*s++ = 0x30;
407	if (msglen < 128) {
408		if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
409			trapmsglen = 2;
410		else
411			trapmsglen = 1;
412	} else {
413		if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
414			trapmsglen = 2;
415		else
416			trapmsglen = 1;
417	}
418	t = s + trapmsglen;
419	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
420	t += sizeof(ipf_trap0_2);
421
422	*t++ = 0x4;		/* Octet string */
423	n = writelength(t, msglen);
424	t += n;
425	bcopy(msg, t, msglen);
426	t += msglen;
427
428	len = t - s - trapmsglen;
429	writelength(s, len);
430
431	len = t - varlen - varlensz;
432	writelength(varlen, len);		/* pdu length */
433
434	len = t - pdulen - pdulensz;
435	writelength(pdulen, len);		/* pdu length */
436
437	len = t - buffer - baselensz - 1;
438	writelength(buffer + 1, len);	/* length of trap */
439
440	return t - buffer;
441}
442
443
444int
445sendtrap_v2_0(fd, community, msg, msglen)
446	int fd;
447	char *community, *msg;
448	int msglen;
449{
450
451	u_char buffer[1500];
452	int n;
453
454	n = maketrap_v2(community, buffer, sizeof(buffer),
455			(u_char *)msg, msglen);
456	if (n > 0) {
457		return send(fd, buffer, n, 0);
458	}
459
460	return 0;
461}
462