|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Copyright (c) 2015, Arista Networks, inc.
|
|
Packit |
fcad23 |
* All rights reserved.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fcad23 |
* modification, are permitted provided that the following conditions
|
|
Packit |
fcad23 |
* are met:
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
fcad23 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fcad23 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
fcad23 |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* 3. Neither the name of the copyright holder nor the names of its
|
|
Packit |
fcad23 |
* contributors may be used to endorse or promote products derived from
|
|
Packit |
fcad23 |
* this software without specific prior written permission.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
fcad23 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
fcad23 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
fcad23 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
fcad23 |
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
fcad23 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
fcad23 |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
fcad23 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
fcad23 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
fcad23 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
fcad23 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
#include <net-snmp/net-snmp-config.h>
|
|
Packit |
fcad23 |
#include <net-snmp/net-snmp-includes.h>
|
|
Packit |
fcad23 |
#include <net-snmp/library/large_fd_set.h>
|
|
Packit |
fcad23 |
#include <stdio.h>
|
|
Packit |
fcad23 |
#include <unistd.h>
|
|
Packit |
fcad23 |
#include <sys/types.h>
|
|
Packit |
fcad23 |
#include <sys/stat.h>
|
|
Packit |
fcad23 |
#include <fcntl.h>
|
|
Packit |
fcad23 |
#include <pcap/pcap.h>
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
#define FAKE_FD 3
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* This is a funny little program, hooking together callbacks
|
|
Packit |
fcad23 |
* to get packets from a pcap format file to go through
|
|
Packit |
fcad23 |
* net-snmp's main loop. Both net-snmp and libpcap have
|
|
Packit |
fcad23 |
* callback-based processing, so:
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* We create a fake snmp transport that calls snmppcap_recv()
|
|
Packit |
fcad23 |
* to receive a packet, and use snmp_add() to add the session
|
|
Packit |
fcad23 |
* and the transport directly.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* We create a session callback on the session that just
|
|
Packit |
fcad23 |
* prints out the varbind list that we got.
|
|
Packit |
fcad23 |
*
|
|
Packit |
fcad23 |
* We use the libpcap pcap_dispatch() to loop through all
|
|
Packit |
fcad23 |
* the packets in the pcap file, and then pretend to snmp_read2()
|
|
Packit |
fcad23 |
* that a fake file descriptor is ready. Luckily, there is
|
|
Packit |
fcad23 |
* only one session active, and it happens to also claim to
|
|
Packit |
fcad23 |
* be using that file descriptor, so snmplib calls the transport
|
|
Packit |
fcad23 |
* receive function, snmppcap_recv(). If the packet parses,
|
|
Packit |
fcad23 |
* we get a callback at snmppcap_callback(). If it doesn't,
|
|
Packit |
fcad23 |
* you may need to use the -D options.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
typedef struct mystuff {
|
|
Packit |
fcad23 |
int pktnum;
|
|
Packit |
fcad23 |
} mystuff_t;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* These two globals are used to communicate between handle_pcap()
|
|
Packit |
fcad23 |
* and snmppcap_recv(). Don't try to multi-thread! :-)
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
const void *recv_data;
|
|
Packit |
fcad23 |
int recv_datalen;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
int
|
|
Packit |
fcad23 |
snmppcap_recv(netsnmp_transport *t, void *buf, int bufsiz, void **opaque, int *opaque_len)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
if (bufsiz > recv_datalen) {
|
|
Packit |
fcad23 |
memcpy(buf, recv_data, recv_datalen);
|
|
Packit |
fcad23 |
return recv_datalen;
|
|
Packit |
fcad23 |
} else {
|
|
Packit |
fcad23 |
return -1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* snmplib calls us back with the received packet.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
static int
|
|
Packit |
fcad23 |
snmppcap_callback(int op, netsnmp_session *sess, int reqid, netsnmp_pdu *pdu,
|
|
Packit |
fcad23 |
void *magic)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
mystuff_t *mystuff = (mystuff_t *)magic;
|
|
Packit |
fcad23 |
netsnmp_variable_list *vars;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* We ignore op, since we know there is only way we can be
|
|
Packit |
fcad23 |
* called back, since this is not a "real" transport.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
printf( "Packet %d PDU contents:\n", mystuff->pktnum );
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* TODO: print PDU type and other info?
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
for (vars = pdu->variables; vars; vars = vars->next_variable) {
|
|
Packit |
fcad23 |
printf( " " );
|
|
Packit |
fcad23 |
print_variable(vars->name, vars->name_length, vars );
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
return 0;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
void
|
|
Packit |
fcad23 |
handle_pcap(u_char *user, const struct pcap_pkthdr *h,
|
|
Packit |
fcad23 |
const u_char *bytes)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
size_t len;
|
|
Packit |
fcad23 |
const u_char *buf;
|
|
Packit |
fcad23 |
int skip;
|
|
Packit |
fcad23 |
mystuff_t *mystuff = (mystuff_t *)user;
|
|
Packit |
fcad23 |
netsnmp_large_fd_set lfdset;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
mystuff->pktnum++;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* If it's not a full packet, then we can't parse it.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
if ( h->caplen < h->len ) {
|
|
Packit |
fcad23 |
printf( "Skipping packet #%d; we only have %d of %d bytes\n", mystuff->pktnum, h->caplen, h->len );
|
|
Packit |
fcad23 |
return;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* For now, no error checking and almost no parsing.
|
|
Packit |
fcad23 |
* Assume that we have all Ethernet/IPv4/UDP/SNMP.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
skip = 14 /* Ethernet */ + 20 /* IPv4 */ + 8 /* UDP */;
|
|
Packit |
fcad23 |
buf = bytes + skip;
|
|
Packit |
fcad23 |
len = h->len - skip;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
printf( "Packet #%d:\n", mystuff->pktnum );
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* Store the data in the globals that we use to communicate
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
recv_data = buf;
|
|
Packit |
fcad23 |
recv_datalen = len;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* We call snmp_read2() pretending that our
|
|
Packit |
fcad23 |
* fake file descriptor is ready to read.
|
|
Packit |
fcad23 |
* This is a funny API to fake up - we need to
|
|
Packit |
fcad23 |
* set our fake file descriptor so that our fake
|
|
Packit |
fcad23 |
* receive function gets called.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
|
|
Packit |
fcad23 |
netsnmp_large_fd_setfd(FAKE_FD, &lfdset);
|
|
Packit |
fcad23 |
snmp_read2(&lfdset);
|
|
Packit |
fcad23 |
netsnmp_large_fd_set_cleanup(&lfdset);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
void
|
|
Packit |
fcad23 |
usage(void)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
fprintf(stderr, "USAGE: snmppcap [OPTIONS] FILE\n\n");
|
|
Packit |
fcad23 |
/* can't use snmp_parse_args_usage because it assumes an agent */
|
|
Packit |
fcad23 |
snmp_parse_args_descriptions(stderr);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
int main(int argc, char **argv)
|
|
Packit |
fcad23 |
{
|
|
Packit |
fcad23 |
netsnmp_session *ss;
|
|
Packit |
fcad23 |
netsnmp_transport *transport;
|
|
Packit |
fcad23 |
int arg;
|
|
Packit |
fcad23 |
char errbuf[PCAP_ERRBUF_SIZE];
|
|
Packit |
fcad23 |
char *fname;
|
|
Packit |
fcad23 |
pcap_t *p;
|
|
Packit |
fcad23 |
mystuff_t mystuff;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
ss = SNMP_MALLOC_TYPEDEF(netsnmp_session);
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* snmp_parse_args usage here is totally overkill, but trying to
|
|
Packit |
fcad23 |
* parse -D
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
switch (arg = snmp_parse_args(argc, argv, ss, "", NULL)) {
|
|
Packit |
fcad23 |
case NETSNMP_PARSE_ARGS_ERROR:
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
|
|
Packit |
fcad23 |
exit(0);
|
|
Packit |
fcad23 |
case NETSNMP_PARSE_ARGS_ERROR_USAGE:
|
|
Packit |
fcad23 |
usage();
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
default:
|
|
Packit |
fcad23 |
break;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if (arg != argc) {
|
|
Packit |
fcad23 |
fprintf(stderr, "Specify exactly one file name\n");
|
|
Packit |
fcad23 |
usage();
|
|
Packit |
fcad23 |
exit(1);
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
fname = argv[ arg-1 ];
|
|
Packit |
fcad23 |
p = pcap_open_offline( fname, errbuf );
|
|
Packit |
fcad23 |
if ( p == NULL ) {
|
|
Packit |
fcad23 |
fprintf(stderr, "%s: %s\n", fname, errbuf );
|
|
Packit |
fcad23 |
return 1;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
if ( pcap_datalink( p ) != DLT_EN10MB) {
|
|
Packit |
fcad23 |
fprintf(stderr, "Only Ethernet pcaps currently supported\n");
|
|
Packit |
fcad23 |
return 2;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
transport = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
|
|
Packit |
fcad23 |
if ( transport == NULL ) {
|
|
Packit |
fcad23 |
fprintf(stderr, "Could not malloc transport\n" );
|
|
Packit |
fcad23 |
return 3;
|
|
Packit |
fcad23 |
}
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* We set up just enough of the transport to fake the main
|
|
Packit |
fcad23 |
* loop into calling us back.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
transport->sock = FAKE_FD; /* nobody actually uses this as a file descriptor */
|
|
Packit |
fcad23 |
transport->f_recv = snmppcap_recv;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
ss->callback = snmppcap_callback;
|
|
Packit |
fcad23 |
ss->callback_magic = (void *)&mystuff;
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/* todo: add the option of a filter here */
|
|
Packit |
fcad23 |
mystuff.pktnum = 0;
|
|
Packit |
fcad23 |
/* todo: user, etc. parsing. */
|
|
Packit |
fcad23 |
ss->securityModel = SNMP_SEC_MODEL_USM;
|
|
Packit |
fcad23 |
printf("flags %lx securityModel %d version %ld securityNameLen %" NETSNMP_PRIz "d securityEngineIDLen %" NETSNMP_PRIz "d\n",
|
|
Packit |
fcad23 |
ss->flags, ss->securityModel, ss->version,
|
|
Packit |
fcad23 |
ss->securityNameLen, ss->securityEngineIDLen);
|
|
Packit |
fcad23 |
create_user_from_session(ss);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
/*
|
|
Packit |
fcad23 |
* We use snmp_add() to specify the transport
|
|
Packit |
fcad23 |
* explicitly.
|
|
Packit |
fcad23 |
*/
|
|
Packit |
fcad23 |
snmp_add(ss, transport, NULL, NULL);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
pcap_loop(p, -1, handle_pcap, (void *)&mystuff);
|
|
Packit |
fcad23 |
|
|
Packit |
fcad23 |
return 0;
|
|
Packit |
fcad23 |
}
|