1258331Smarkj#include "ipf.h"
2266991Skevlo#include "netinet/ipl.h"
3258331Smarkj#include "ipmon.h"
4258331Smarkj#include <ctype.h>
5258331Smarkj
6258331Smarkj#define	IPF_ENTERPRISE	9932
7258331Smarkj/*
8258331Smarkj * Enterprise number OID:
9258331Smarkj * 1.3.6.1.4.1.9932
10258331Smarkj */
11258331Smarkjstatic u_char ipf_enterprise[] = { 6, 7, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c };
12258331Smarkjstatic u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
13258331Smarkjstatic u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
14258331Smarkj
15258331Smarkjstatic int writeint __P((u_char *, int));
16258331Smarkjstatic int writelength __P((u_char *, u_int));
17258331Smarkjstatic int maketrap_v1 __P((char *, u_char *, int, u_char *, int, u_32_t,
18258331Smarkj			    time_t));
19258331Smarkjstatic void snmpv1_destroy __P((void *));
20258331Smarkjstatic void *snmpv1_dup __P((void *));
21258331Smarkjstatic int snmpv1_match __P((void *, void *));
22258331Smarkjstatic void *snmpv1_parse __P((char **));
23258331Smarkjstatic void snmpv1_print __P((void *));
24258331Smarkjstatic int snmpv1_send __P((void *, ipmon_msg_t *));
25258331Smarkj
26258331Smarkjtypedef struct snmpv1_opts_s {
27258331Smarkj	char			*community;
28258331Smarkj	int			fd;
29258331Smarkj	int			v6;
30258331Smarkj	int			ref;
31258331Smarkj#ifdef USE_INET6
32258331Smarkj	struct sockaddr_in6	sin6;
33258331Smarkj#endif
34258331Smarkj	struct sockaddr_in	sin;
35258331Smarkj} snmpv1_opts_t;
36258331Smarkj
37258331Smarkjipmon_saver_t snmpv1saver = {
38258331Smarkj	"snmpv1",
39258331Smarkj	snmpv1_destroy,
40258331Smarkj	snmpv1_dup,		/* dup */
41258331Smarkj	snmpv1_match,		/* match */
42258331Smarkj	snmpv1_parse,
43258331Smarkj	snmpv1_print,
44258331Smarkj	snmpv1_send
45258331Smarkj};
46258331Smarkj
47258331Smarkj
48258331Smarkjstatic int
49258331Smarkjsnmpv1_match(ctx1, ctx2)
50258331Smarkj	void *ctx1, *ctx2;
51258331Smarkj{
52258331Smarkj	snmpv1_opts_t *s1 = ctx1, *s2 = ctx2;
53258331Smarkj
54258331Smarkj	if (s1->v6 != s2->v6)
55258331Smarkj		return 1;
56258331Smarkj
57258331Smarkj	if (strcmp(s1->community, s2->community))
58258331Smarkj		return 1;
59258331Smarkj
60258331Smarkj#ifdef USE_INET6
61258331Smarkj	if (s1->v6 == 1) {
62258331Smarkj		if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
63258331Smarkj			return 1;
64258331Smarkj	} else
65258331Smarkj#endif
66258331Smarkj	{
67258331Smarkj		if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
68258331Smarkj			return 1;
69266991Skevlo	}
70266991Skevlo
71258331Smarkj	return 0;
72258331Smarkj}
73258331Smarkj
74258331Smarkj
75266991Skevlostatic void *
76266991Skevlosnmpv1_dup(ctx)
77266991Skevlo	void *ctx;
78266991Skevlo{
79266991Skevlo	snmpv1_opts_t *s = ctx;
80268737Shselasky
81266991Skevlo	s->ref++;
82266991Skevlo	return s;
83266991Skevlo}
84266991Skevlo
85258331Smarkj
86258331Smarkjstatic void
87258331Smarkjsnmpv1_print(ctx)
88258331Smarkj	void *ctx;
89258331Smarkj{
90258331Smarkj	snmpv1_opts_t *snmpv1 = ctx;
91258331Smarkj
92258331Smarkj	printf("%s ", snmpv1->community);
93258331Smarkj#ifdef USE_INET6
94258331Smarkj	if (snmpv1->v6 == 1) {
95258331Smarkj		char buf[80];
96258331Smarkj
97258331Smarkj		printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf,
98258331Smarkj				       sizeof(snmpv1->sin6.sin6_addr)));
99258331Smarkj	} else
100258331Smarkj#endif
101258331Smarkj	{
102258331Smarkj		printf("%s", inet_ntoa(snmpv1->sin.sin_addr));
103258331Smarkj	}
104258331Smarkj}
105258331Smarkj
106258331Smarkj
107258331Smarkjstatic void *
108258331Smarkjsnmpv1_parse(char **strings)
109258331Smarkj{
110258331Smarkj	snmpv1_opts_t *ctx;
111258331Smarkj	int result;
112266991Skevlo	char *str;
113258331Smarkj	char *s;
114258331Smarkj
115258331Smarkj	if (strings[0] == NULL || strings[0][0] == '\0')
116266991Skevlo		return NULL;
117258331Smarkj
118258331Smarkj	if (strchr(*strings, ' ') == NULL)
119258331Smarkj		return NULL;
120258331Smarkj
121258331Smarkj	str = strdup(*strings);
122258331Smarkj
123258331Smarkj	ctx = calloc(1, sizeof(*ctx));
124258331Smarkj	if (ctx == NULL)
125258331Smarkj		return NULL;
126268219Shselasky
127268219Shselasky	ctx->fd = -1;
128266991Skevlo
129258331Smarkj	s = strchr(str, ' ');
130258331Smarkj	*s++ = '\0';
131258331Smarkj	ctx->community = str;
132258331Smarkj
133258331Smarkj	while (ISSPACE(*s))
134258331Smarkj		s++;
135258331Smarkj	if (!*s) {
136258331Smarkj		free(str);
137258331Smarkj		free(ctx);
138258331Smarkj		return NULL;
139258331Smarkj	}
140258331Smarkj
141258331Smarkj#ifdef USE_INET6
142258331Smarkj	if (strchr(s, ':') == NULL) {
143258331Smarkj		result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
144258331Smarkj		if (result == 1) {
145258331Smarkj			ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
146258331Smarkj			if (ctx->fd >= 0) {
147266991Skevlo				ctx->sin.sin_family = AF_INET;
148258331Smarkj				ctx->sin.sin_port = htons(162);
149258331Smarkj				if (connect(ctx->fd,
150258331Smarkj					    (struct sockaddr *)&ctx->sin,
151258331Smarkj					    sizeof(ctx->sin)) != 0) {
152258331Smarkj						snmpv1_destroy(ctx);
153258331Smarkj						return NULL;
154258331Smarkj				}
155258331Smarkj			}
156268737Shselasky		}
157258331Smarkj	} else {
158258331Smarkj		result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
159258331Smarkj		if (result == 1) {
160258331Smarkj			ctx->v6 = 1;
161258331Smarkj			ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
162258331Smarkj			if (ctx->fd >= 0) {
163258331Smarkj				ctx->sin6.sin6_family = AF_INET6;
164258331Smarkj				ctx->sin6.sin6_port = htons(162);
165258331Smarkj				if (connect(ctx->fd,
166258331Smarkj					    (struct sockaddr *)&ctx->sin6,
167258331Smarkj					    sizeof(ctx->sin6)) != 0) {
168258331Smarkj						snmpv1_destroy(ctx);
169258331Smarkj						return NULL;
170258331Smarkj				}
171258331Smarkj			}
172258331Smarkj		}
173258331Smarkj	}
174258331Smarkj#else
175258331Smarkj	result = inet_aton(s, &ctx->sin.sin_addr);
176258331Smarkj	if (result == 1) {
177258331Smarkj		ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
178258331Smarkj		if (ctx->fd >= 0) {
179258331Smarkj			ctx->sin.sin_family = AF_INET;
180258331Smarkj			ctx->sin.sin_port = htons(162);
181258331Smarkj			if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
182258331Smarkj				    sizeof(ctx->sin)) != 0) {
183258331Smarkj					snmpv1_destroy(ctx);
184258331Smarkj					return NULL;
185258331Smarkj			}
186258331Smarkj		}
187258331Smarkj	}
188258331Smarkj#endif
189258331Smarkj
190258331Smarkj	if (result != 1) {
191258331Smarkj		free(str);
192258331Smarkj		free(ctx);
193258331Smarkj		return NULL;
194258331Smarkj	}
195258331Smarkj
196258331Smarkj	ctx->ref = 1;
197258331Smarkj
198258331Smarkj	return ctx;
199258331Smarkj}
200258331Smarkj
201258331Smarkj
202258331Smarkjstatic void
203258331Smarkjsnmpv1_destroy(ctx)
204258331Smarkj	void *ctx;
205258331Smarkj{
206258331Smarkj	snmpv1_opts_t *v1 = ctx;
207258331Smarkj
208258331Smarkj	v1->ref--;
209258331Smarkj	if (v1->ref > 0)
210258331Smarkj		return;
211258331Smarkj
212258331Smarkj	if (v1->community)
213258331Smarkj		free(v1->community);
214258331Smarkj	if (v1->fd >= 0)
215258331Smarkj		close(v1->fd);
216258331Smarkj	free(v1);
217258331Smarkj}
218258331Smarkj
219258331Smarkj
220258331Smarkjstatic int
221258331Smarkjsnmpv1_send(ctx, msg)
222258331Smarkj	void *ctx;
223258331Smarkj	ipmon_msg_t *msg;
224258331Smarkj{
225258331Smarkj	snmpv1_opts_t *v1 = ctx;
226258331Smarkj
227258331Smarkj	return sendtrap_v1_0(v1->fd, v1->community,
228258331Smarkj			     msg->imm_msg, msg->imm_msglen, msg->imm_when);
229258331Smarkj}
230258331Smarkj
231258331Smarkjstatic char def_community[] = "public";	/* ublic */
232258331Smarkj
233258331Smarkjstatic int
234258331Smarkjwritelength(buffer, value)
235258331Smarkj	u_char *buffer;
236258331Smarkj	u_int value;
237258331Smarkj{
238258331Smarkj	u_int n = htonl(value);
239258331Smarkj	int len;
240258331Smarkj
241258331Smarkj	if (value < 128) {
242266991Skevlo		*buffer = value;
243266991Skevlo		return 1;
244266991Skevlo	}
245266991Skevlo	if (value > 0xffffff)
246266991Skevlo		len = 4;
247266991Skevlo	else if (value > 0xffff)
248266991Skevlo		len = 3;
249266991Skevlo	else if (value > 0xff)
250266991Skevlo		len = 2;
251258331Smarkj	else
252258331Smarkj		len = 1;
253258331Smarkj
254258331Smarkj	*buffer = 0x80 | len;
255258331Smarkj
256258331Smarkj	bcopy((u_char *)&n + 4 - len, buffer + 1, len);
257258331Smarkj
258258331Smarkj	return len + 1;
259258331Smarkj}
260258331Smarkj
261258331Smarkj
262266991Skevlostatic int
263258331Smarkjwriteint(buffer, value)
264266991Skevlo	u_char *buffer;
265258331Smarkj	int value;
266258331Smarkj{
267258331Smarkj	u_char *s = buffer;
268258331Smarkj	u_int n = value;
269258331Smarkj
270258331Smarkj	if (value == 0) {
271258331Smarkj		*buffer = 0;
272258331Smarkj		return 1;
273258331Smarkj	}
274258331Smarkj
275258331Smarkj	if (n >  4194304) {
276258331Smarkj		*s++ = 0x80 | (n / 4194304);
277258331Smarkj		n -= 4194304 * (n / 4194304);
278258331Smarkj	}
279258331Smarkj	if (n >  32768) {
280258331Smarkj		*s++ = 0x80 | (n / 32768);
281258331Smarkj		n -= 32768 * (n / 327678);
282258331Smarkj	}
283258331Smarkj	if (n > 128) {
284258331Smarkj		*s++ = 0x80 | (n / 128);
285258331Smarkj		n -= (n / 128) * 128;
286258331Smarkj	}
287258331Smarkj	*s++ = (u_char)n;
288258331Smarkj
289258331Smarkj	return s - buffer;
290258331Smarkj}
291258331Smarkj
292258331Smarkj
293258331Smarkj
294258331Smarkj/*
295258331Smarkj * First style of traps is:
296258331Smarkj * 1.3.6.1.4.1.9932.1.1
297258331Smarkj */
298258331Smarkjstatic int
299258331Smarkjmaketrap_v1(community, buffer, bufsize, msg, msglen, ipaddr, when)
300258331Smarkj	char *community;
301258331Smarkj	u_char *buffer;
302258331Smarkj	int bufsize;
303258331Smarkj	u_char *msg;
304258331Smarkj	int msglen;
305258331Smarkj	u_32_t ipaddr;
306258331Smarkj	time_t when;
307258331Smarkj{
308258331Smarkj	u_char *s = buffer, *t, *pdulen, *varlen;
309258331Smarkj	int basesize = 73;
310258331Smarkj	u_short len;
311258331Smarkj	int trapmsglen;
312258331Smarkj	int pdulensz;
313258331Smarkj	int varlensz;
314258331Smarkj	int baselensz;
315258331Smarkj	int n;
316258331Smarkj
317258331Smarkj	if (community == NULL || *community == '\0')
318258331Smarkj		community = def_community;
319258331Smarkj	basesize += strlen(community) + msglen;
320258331Smarkj
321258331Smarkj	if (basesize + 8 > bufsize)
322258331Smarkj		return 0;
323258331Smarkj
324266991Skevlo	memset(buffer, 0xff, bufsize);
325258331Smarkj	*s++ = 0x30;		/* Sequence */
326258331Smarkj	if (basesize - 1 >= 128) {
327258331Smarkj		baselensz = 2;
328258331Smarkj		basesize++;
329258331Smarkj	} else {
330258331Smarkj		baselensz = 1;
331258331Smarkj	}
332258331Smarkj	s += baselensz;
333258331Smarkj	*s++ = 0x02;		/* Integer32 */
334258331Smarkj	*s++ = 0x01;		/* length 1 */
335258331Smarkj	*s++ = 0x00;		/* version 1 */
336258331Smarkj	*s++ = 0x04;		/* octet string */
337258331Smarkj	*s++ = strlen(community);		/* length of "public" */
338258331Smarkj	bcopy(community, s, s[-1]);
339258331Smarkj	s += s[-1];
340258331Smarkj	*s++ = 0xA4;		/* PDU(4) */
341258331Smarkj	pdulen = s++;
342258331Smarkj	if (basesize - (s - buffer) >= 128) {
343258331Smarkj		pdulensz = 2;
344258331Smarkj		basesize++;
345258331Smarkj		s++;
346258331Smarkj	} else {
347258331Smarkj		pdulensz = 1;
348258331Smarkj	}
349258331Smarkj
350258331Smarkj	/* enterprise */
351258331Smarkj	bcopy(ipf_enterprise, s, sizeof(ipf_enterprise));
352258331Smarkj	s += sizeof(ipf_enterprise);
353258331Smarkj
354258331Smarkj	/* Agent address */
355258331Smarkj	*s++ = 0x40;
356258331Smarkj	*s++ = 0x4;
357266991Skevlo	bcopy(&ipaddr, s, 4);
358266991Skevlo	s += 4;
359258331Smarkj
360258331Smarkj	/* Generic Trap code */
361266991Skevlo	*s++ = 0x2;
362258331Smarkj	n = writeint(s + 1, 6);
363266991Skevlo	if (n == 0)
364258331Smarkj		return 0;
365266991Skevlo	*s = n;
366258331Smarkj	s += n + 1;
367266991Skevlo
368258331Smarkj	/* Specific Trap code */
369258331Smarkj	*s++ = 0x2;
370266991Skevlo	n = writeint(s + 1, 0);
371266991Skevlo	if (n == 0)
372266991Skevlo		return 0;
373266991Skevlo	*s = n;
374266991Skevlo	s += n + 1;
375266991Skevlo
376266991Skevlo	/* Time stamp */
377266991Skevlo	*s++ = 0x43;			/* TimeTicks */
378258331Smarkj	*s++ = 0x04;			/* TimeTicks */
379266991Skevlo	s[0] = when >> 24;
380266991Skevlo	s[1] = when >> 16;
381266991Skevlo	s[2] = when >> 8;
382266991Skevlo	s[3] = when & 0xff;
383266991Skevlo	s += 4;
384266991Skevlo
385258331Smarkj	/*
386266991Skevlo	 * The trap0 message is "ipfilter_version" followed by the message
387258331Smarkj	 */
388258331Smarkj	*s++ = 0x30;
389266991Skevlo	varlen = s;
390266991Skevlo	if (basesize - (s - buffer) >= 128) {
391266991Skevlo		varlensz = 2;
392258331Smarkj		basesize++;
393258331Smarkj	} else {
394258331Smarkj		varlensz = 1;
395258331Smarkj	}
396258331Smarkj	s += varlensz;
397258331Smarkj
398258331Smarkj	*s++ = 0x30;
399258331Smarkj	t = s + 1;
400258331Smarkj	bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
401266991Skevlo	t += sizeof(ipf_trap0_1);
402266991Skevlo
403258331Smarkj	*t++ = 0x2;		/* Integer */
404266991Skevlo	n = writeint(t + 1, IPFILTER_VERSION);
405258331Smarkj	*t = n;
406258331Smarkj	t += n + 1;
407258331Smarkj
408258331Smarkj	len = t - s - 1;
409258331Smarkj	writelength(s, len);
410258331Smarkj
411258331Smarkj	s = t;
412258331Smarkj	*s++ = 0x30;
413258331Smarkj	if (basesize - (s - buffer) >= 128) {
414258331Smarkj		trapmsglen = 2;
415258331Smarkj		basesize++;
416258331Smarkj	} else {
417258331Smarkj		trapmsglen = 1;
418258331Smarkj	}
419258331Smarkj	t = s + trapmsglen;
420258331Smarkj	bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
421258331Smarkj	t += sizeof(ipf_trap0_2);
422258331Smarkj
423258331Smarkj	*t++ = 0x4;		/* Octet string */
424258331Smarkj	n = writelength(t, msglen);
425258331Smarkj	t += n;
426258331Smarkj	bcopy(msg, t, msglen);
427258331Smarkj	t += msglen;
428258331Smarkj
429258331Smarkj	len = t - s - trapmsglen;
430258331Smarkj	writelength(s, len);
431258331Smarkj
432258331Smarkj	len = t - varlen - varlensz;
433258331Smarkj	writelength(varlen, len);		/* pdu length */
434258331Smarkj
435258331Smarkj	len = t - pdulen - pdulensz;
436258331Smarkj	writelength(pdulen, len);		/* pdu length */
437258331Smarkj
438258331Smarkj	len = t - buffer - baselensz - 1;
439266991Skevlo	writelength(buffer + 1, len);	/* length of trap */
440258331Smarkj
441258331Smarkj	return t - buffer;
442258331Smarkj}
443258331Smarkj
444258331Smarkj
445258331Smarkjint
446258331Smarkjsendtrap_v1_0(fd, community, msg, msglen, when)
447258331Smarkj	int fd;
448258331Smarkj	char *community, *msg;
449258331Smarkj	int msglen;
450258331Smarkj	time_t when;
451258331Smarkj{
452258331Smarkj
453258331Smarkj	u_char buffer[1500];
454258331Smarkj	int n;
455258331Smarkj
456258331Smarkj	n = maketrap_v1(community, buffer, sizeof(buffer),
457258331Smarkj			(u_char *)msg, msglen, 0, when);
458258331Smarkj	if (n > 0) {
459258331Smarkj		return send(fd, buffer, n, 0);
460258331Smarkj	}
461258331Smarkj
462258331Smarkj	return 0;
463258331Smarkj}
464258331Smarkj