Merge release 1.14 of bsnmp.

This commit is contained in:
Hartmut Brandt 2020-04-01 15:25:16 +00:00
commit 0bf56da32d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=359512
16 changed files with 19721 additions and 89 deletions

View file

@ -65,8 +65,8 @@ asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
return (ASN_ERR_EOBUF);
}
*type = *b->asn_cptr;
if ((*type & ASN_TYPE_MASK) > 0x30) {
asn_error(b, "types > 0x30 not supported (%u)",
if ((*type & ASN_TYPE_MASK) > 0x1e) {
asn_error(b, "tags > 0x1e not supported (%#x)",
*type & ASN_TYPE_MASK);
return (ASN_ERR_FAILED);
}
@ -100,11 +100,19 @@ asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
*len = *b->asn_cptr++;
b->asn_len--;
}
#ifdef BOGUS_CVE_2019_5610_FIX
/*
* This is the fix from CVE-2019-5610.
*
* This is the wrong place. Each of the asn functions should check
* that it has enough info for its own work.
*/
if (*len > b->asn_len) {
asn_error(b, "len %u exceeding asn_len %u", *len, b->asn_len);
asn_error(b, "lenen %u exceeding asn_len %u", *len, b->asn_len);
return (ASN_ERR_EOBUF);
}
#endif
return (ASN_ERR_OK);
}
@ -147,7 +155,7 @@ asn_put_len(u_char *ptr, asn_len_t len)
/*
* Write a header (tag and length fields).
* Tags are restricted to one byte tags (value <= 0x30) and the
* Tags are restricted to one byte tags (value <= 0x1e) and the
* lenght field to 16-bit. All errors stop the encoding.
*/
enum asn_err
@ -156,8 +164,8 @@ asn_put_header(struct asn_buf *b, u_char type, asn_len_t len)
u_int lenlen;
/* tag field */
if ((type & ASN_TYPE_MASK) > 0x30) {
asn_error(NULL, "types > 0x30 not supported (%u)",
if ((type & ASN_TYPE_MASK) > 0x1e) {
asn_error(NULL, "types > 0x1e not supported (%#x)",
type & ASN_TYPE_MASK);
return (ASN_ERR_FAILED);
}
@ -251,9 +259,10 @@ asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp)
return (ASN_ERR_BADLEN);
}
err = ASN_ERR_OK;
if (len > 8)
if (len > 8) {
asn_error(b, "integer too long");
err = ASN_ERR_RANGE;
else if (len > 1 &&
} else if (len > 1 &&
((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) ||
(*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) {
asn_error(b, "non-minimal integer");
@ -331,27 +340,35 @@ asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival)
static enum asn_err
asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp)
{
enum asn_err err;
*vp = 0;
if (b->asn_len < len) {
asn_error(b, "truncated integer");
return (ASN_ERR_EOBUF);
}
if (len == 0) {
/* X.690: 8.3.1 */
asn_error(b, "zero-length integer");
*vp = 0;
return (ASN_ERR_BADLEN);
}
err = ASN_ERR_OK;
*vp = 0;
if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) {
if (len > 1 && *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) {
/* X.690: 8.3.2 */
asn_error(b, "non-minimal unsigned");
b->asn_cptr += len;
b->asn_len -= len;
return (ASN_ERR_BADLEN);
}
enum asn_err err = ASN_ERR_OK;
if ((*b->asn_cptr & 0x80) || len > 9 ||
(len == 9 && *b->asn_cptr != 0)) {
/* negative integer or too larger */
*vp = 0xffffffffffffffffULL;
err = ASN_ERR_RANGE;
} else if (len > 1 &&
*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) {
asn_error(b, "non-minimal unsigned");
err = ASN_ERR_BADLEN;
asn_error(b, "unsigned too large or negative");
b->asn_cptr += len;
b->asn_len -= len;
return (ASN_ERR_RANGE);
}
while (len--) {
@ -405,11 +422,14 @@ asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp)
enum asn_err ret;
if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) {
if (len > 4)
if (len > 4) {
asn_error(b, "integer too long");
ret = ASN_ERR_BADLEN;
else if (val > INT32_MAX || val < INT32_MIN)
} else if (val > INT32_MAX || val < INT32_MIN) {
/* may not happen */
asn_error(b, "integer out of range");
ret = ASN_ERR_RANGE;
}
*vp = (int32_t)val;
}
return (ret);
@ -589,7 +609,7 @@ asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid)
return (ASN_ERR_EOBUF);
}
if (subid > (ASN_MAXID >> 7)) {
asn_error(b, "OBID subid too larger");
asn_error(b, "OID subid too larger");
err = ASN_ERR_RANGE;
}
subid = (subid << 7) | (*b->asn_cptr & 0x7f);
@ -645,7 +665,7 @@ asn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
oidlen = 2;
} else if (oid->len == 1) {
/* illegal */
asn_error(b, "short oid");
asn_error(NULL, "short oid");
if (oid->subs[0] > 2)
asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]);
err = ASN_ERR_RANGE;
@ -657,7 +677,8 @@ asn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
err = ASN_ERR_RANGE;
}
if (oid->subs[0] > 2 ||
(oid->subs[0] < 2 && oid->subs[1] >= 40)) {
(oid->subs[0] < 2 && oid->subs[1] >= 40) ||
(oid->subs[0] == 2 && oid->subs[1] > ASN_MAXID - 2 * 40)) {
asn_error(NULL, "oid out of range (%u,%u)",
oid->subs[0], oid->subs[1]);
err = ASN_ERR_RANGE;
@ -814,10 +835,7 @@ asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp)
enum asn_err err;
if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) {
if (len > 5) {
asn_error(b, "uint32 too long %u", len);
err = ASN_ERR_BADLEN;
} else if (v > UINT32_MAX) {
if (v > UINT32_MAX) {
asn_error(b, "uint32 too large %llu", v);
err = ASN_ERR_RANGE;
}

View file

@ -31,7 +31,7 @@
.\"
.\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $
.\"
.Dd December 31, 2016
.Dd March 31, 2020
.Dt BSNMPCLIENT 3
.Os
.Sh NAME
@ -177,7 +177,9 @@ If it is
a local stream socket is used.
For
.Dv SNMP_TRANS_UDP
a UDP socket is created.
a UDPv4 socket and for
.Dv SNMP_TRANS_UDP6
a UDPv6 socket is created.
It uses the
.Va chost
field as the path to the server's socket for local sockets.
@ -675,7 +677,12 @@ The syntax of a server specification is
.Pp
where
.Va trans
is the transport name (one of udp, stream or dgram),
is the transport name (one of
.Qq udp ,
.Qq udp6 ,
.Qq stream
or
.Qq dgram ) ,
.Va community
is the string to be used for both the read and the write community,
.Va server
@ -685,13 +692,51 @@ of a local socket, and
is the port in case of UDP transport.
The function returns 0 in the case of success and return -1 and sets
the error string in case of an error.
.Pp
The function
.Fn snmp_parse_serverr
fills the transport, the port number and the community strings with
reasonable default values when they are not specified.
The default transport
is
.Dv SNMP_TRANS_UDP .
If the host name contains a slash the default is modified to
.Dv SNMP_TRANS_LOC_DGRAM .
If the host name looks like a numeric IPv6 address the default is
.Dv SNMP_TRANS_UDP6 .
For numeric IPv6 addresses the transport name udp is automatically
translated as
.Dv SNMP_TRANS_UDP6 .
The default port number (for
.Dv udp
or
.Dv udp6 )
is
.Qq snmp .
The default read community is
.Qq public
and the default write community
.Qq private .
.Pp
.Fn snmp_parse_server
recognizes path names, host names and numerical IPv4 and IPv6 addresses.
A string consisting of digits and periods is assumed to be an IPv4 address
and must be parseable by
.Fn inet_aton 3 .
An IPv6 address is any string enclosed in square brackets.
It must be parseable with
.Fn gethostinfo 3 .
.Pp
The port number for
.Fn snmp_parse_server
can be specified numerically or symbolically.
It is ignored for local sockets.
.Sh DIAGNOSTICS
If an error occurs in any of the function an error indication as described
If an error occurs in any of the functions an error indication as described
above is returned.
Additionally the function sets a printable error string
in the
Additionally the function sets a printable error string in the
.Va error
filed of
field of
.Va snmp_client .
.Sh SEE ALSO
.Xr gensnmptree 1 ,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2005,2018
* Copyright (c) 2004-2005,2018-2019
* Hartmut Brandt.
* All rights reserved.
* Copyright (c) 2001-2003
@ -930,7 +930,7 @@ open_client_udp(const char *host, const char *port)
/* open connection */
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET:
hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET :
AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
@ -1884,7 +1884,8 @@ static const char *const trans_list[] = {
/**
* Try to get a transport identifier which is a leading alphanumeric string
* terminated by a double colon. The string may not be empty. The transport
* identifier is optional.
* identifier is optional. Unknown transport identifiers are reject.
* Be careful: a double colon can also occur in a numeric IPv6 address.
*
* \param sc client struct to set errors
* \param strp possible start of transport; updated to point to
@ -1899,8 +1900,6 @@ get_transp(struct snmp_client *sc, const char **strp)
size_t i;
for (i = 0; i < nitems(trans_list); i++) {
if (trans_list[i] == NULL || *trans_list[i] == '\0')
continue;
p = strstr(*strp, trans_list[i]);
if (p == *strp) {
*strp += strlen(trans_list[i]);
@ -1908,13 +1907,23 @@ get_transp(struct snmp_client *sc, const char **strp)
}
}
p = *strp;
if (p[0] == ':' && p[1] == ':') {
p = strstr(*strp, "::");
if (p == *strp) {
seterr(sc, "empty transport specifier");
return (-1);
}
/* by default assume UDP */
return (SNMP_TRANS_UDP);
if (p == NULL)
/* by default assume UDP */
return (SNMP_TRANS_UDP);
/* ignore :: after [ */
const char *ob = strchr(*strp, '[');
if (ob != NULL && p > ob)
/* by default assume UDP */
return (SNMP_TRANS_UDP);
seterr(sc, "unknown transport specifier '%.*s'", p - *strp, *strp);
return (-1);
}
/**
@ -2153,12 +2162,14 @@ int
snmp_parse_server(struct snmp_client *sc, const char *str)
{
const char *const orig = str;
/* parse input */
int i, trans = get_transp(sc, &str);
int def_trans = 0, trans = get_transp(sc, &str);
if (trans < 0)
return (-1);
/* choose automatically */
i = orig == str ? -1: trans;
if (orig == str)
def_trans = 1;
const char *const comm[2] = {
str,
@ -2204,7 +2215,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
}
#if DEBUG_PARSE
printf("transp: %u\n", trans);
printf("transp: %d (def=%d)\n", trans, def_trans);
printf("comm: %zu %zu\n", comm[0] - orig, comm[1] - orig);
printf("ipv6: %zu %zu\n", ipv6[0] - orig, ipv6[1] - orig);
printf("ipv4: %zu %zu\n", ipv4[0] - orig, ipv4[1] - orig);
@ -2218,18 +2229,19 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
if (ipv6[0] != ipv6[1]) {
if ((chost = save_str(sc, ipv6)) == NULL)
return (-1);
if (i == -1 || trans == SNMP_TRANS_UDP)
if (def_trans || trans == SNMP_TRANS_UDP)
/* assume the user meant udp6:: */
trans = SNMP_TRANS_UDP6;
} else if (ipv4[0] != ipv4[1]) {
if ((chost = save_str(sc, ipv4)) == NULL)
return (-1);
if (i == -1)
if (def_trans)
trans = SNMP_TRANS_UDP;
} else {
if ((chost = save_str(sc, host)) == NULL)
return (-1);
if (i == -1) {
if (def_trans) {
/*
* Default transport is UDP unless the host contains
* a slash in which case we default to DGRAM.
@ -2258,6 +2270,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
/* commit */
sc->trans = trans;
/*
* If community string was specified and it is empty, overwrite it.
* If it was not specified, use default.
@ -2276,7 +2289,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
#if DEBUG_PARSE
printf("Committed values:\n");
printf("trans: %u\n", sc->trans);
printf("trans: %d\n", sc->trans);
printf("comm: '%s'/'%s'\n", sc->read_community, sc->write_community);
printf("host: '%s'\n", sc->chost);
printf("port: '%s'\n", sc->cport);

View file

@ -57,11 +57,11 @@
#define SNMP_AUTH_KEY_LOOPCNT 1048576
#define SNMP_AUTH_BUF_SIZE 72
#ifdef HAVE_LIBCRYPTO
static const uint8_t ipad = 0x36;
static const uint8_t opad = 0x5c;
#ifdef HAVE_LIBCRYPTO
static int32_t
snmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx,
const EVP_MD **dtype, uint32_t *keylen)

View file

@ -447,7 +447,7 @@ mib_fetch_ifmib(struct mibif *ifp)
void *newmib;
struct ifmibdata oldmib = ifp->mib;
struct ifreq irr;
unsigned int alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
u_int alias_maxlen = MIBIF_ALIAS_SIZE_MAX;
if (fetch_generic_mib(ifp, &oldmib) == -1)
return (-1);
@ -519,7 +519,6 @@ mib_fetch_ifmib(struct mibif *ifp)
}
out:
/*
* Find sysctl mib for net.ifdescr_maxlen (one time).
* kmib[0] == -1 at first call to mib_fetch_ifmib().
@ -581,7 +580,7 @@ mib_fetch_ifmib(struct mibif *ifp)
ifp->alias = realloc(ifp->alias, ifp->alias_size);
}
fin:
fin:
ifp->mibtick = get_ticks();
return (0);
}

View file

@ -57,7 +57,7 @@
#include "snmp_mibII.h"
#include "mibII_tree.h"
/* maximum size of the interface alias unless overridden with net.ifdescr_maxlen */
/* maximum size of interface alias unless overridden with net.ifdescr_maxlen */
#define MIBIF_ALIAS_SIZE (64 + 1)
#define MIBIF_ALIAS_SIZE_MAX 1024
@ -81,7 +81,6 @@ struct mibif_private {
uint64_t hc_opackets;
uint64_t hc_imcasts;
uint64_t hc_ipackets;
};
#define MIBIF_PRIV(IFP) ((struct mibif_private *)((IFP)->private))

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2010 The FreeBSD Foundation
* Copyright (c) 2010,2018 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Shteryana Sotirova Shopova under
@ -605,7 +605,7 @@ usm_dump(void)
privstr[uuser->suser.priv_proto]);
}
static const char usm_comment[] = \
static const char usm_comment[] =
"This module implements SNMP User-based Security Model defined in RFC 3414.";
extern const struct snmp_module config;

View file

@ -1013,7 +1013,7 @@ vacm_dump(void)
"excluded":"included");
}
static const char vacm_comment[] = \
static const char vacm_comment[] =
"This module implements SNMP View-based Access Control Model defined in RFC 3415.";
extern const struct snmp_module config;

View file

@ -28,7 +28,7 @@
#
# $Begemot: bsnmp/snmpd/snmpd.config,v 1.16 2006/02/14 09:04:20 brandt_h Exp $
#
# Example configuration file.
# Example configuration file for testing.
#
#
@ -38,56 +38,80 @@ host := foo.bar.com
location := "Room 200"
contact := "sysmeister@bar.com"
system := 1 # FreeBSD
traphost := noc.bar.com
traphost := localhost
trapport := 162
read := "public"
# Uncomment the line below that sets the community string
# to enable write access.
write := "geheim"
write := "geheim" # take care - this allows writing
trap := "mytrap"
securityModelSNMPv1 := 1
securityModelSNMPv2c := 2
noAuthNoPriv := 1
#
# Configuration
#
%snmpd
begemotSnmpdDebugDumpPdus = 2
begemotSnmpdDebugSyslogPri = 7
begemotSnmpdDebugSnmpTrace = 0
#
# Set the read and write communities.
# Set community strings.
#
# The default value of the community strings is NULL (note, that this is
# different from the empty string). This disables both read and write access.
# To enable read access only the read community string must be set. Setting
# the write community string enables both read and write access with that
# string.
# Each community string has a permission attached to it - 1 for read only
# and 2 for read/write. Default is 1. Community strings must be unique.
#
# Be sure to understand the security implications of SNMPv2 - the community
# strings are readable on the wire!
#
begemotSnmpdCommunityString.0.1 = $(read)
# begemotSnmpdCommunityString.0.2 = $(write)
# begemotSnmpdCommunityString.0.3 = "otherPublic"
begemotSnmpdCommunityPermission.0.1 = 1
#begemotSnmpdCommunityString.0.2 = $(write)
#begemotSnmpdCommunityPermission.0.2 = 2
#begemotSnmpdCommunityString.0.3 = "otherPublic"
begemotSnmpdCommunityDisable = 1
# open standard SNMP ports
# begemotSnmpdPortStatus.[$(host)].161 = 1
# begemotSnmpdPortStatus.127.0.0.1.161 = 1
# 0.0.0.0:161
begemotSnmpdTransInetStatus.1.4.0.0.0.0.161.1 = 4
# UDP over IPv4: 127.0.0.1:161
begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4
# test the port table; IPv4 address
# 127.0.0.1:10161
begemotSnmpdTransInetStatus.1.4.127.0.0.1.10161.1 = 4
# UDP over IPv6: ::1:161
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4
# test the port table; IPv6 address
# ::1:10162
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10162.1 = 4
# :::10163
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.10163.1 = 4
# fe80::1%1:10164 - requires inet fe80::1%em0/64
begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.1.10164.1 = 4
# fe80::1%2:10164 - requires inet fe80::1%em1/64
begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.2.10164.1 = 4
# fe80::1:10170 - should fail (no scope index)
# begemotSnmpdTransInetStatus.2.16.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10170.1 = 4
# fe80::1%0:10170 - should fail (default scope index for link local address)
# begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.0.10170.1 = 4
# Use domain name and IPv6 link-local address with scope zone id as address
# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4
# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4
# test the port table; DNS address
# :10165 UDPv4 and UDPv6
begemotSnmpdTransInetStatus.16.0.10165.1 = 4
# 127.0.0.1:10166
# ::1:10166
begemotSnmpdTransInetStatus.16."localhost".10166.1 = 4
# ::1:10167
begemotSnmpdTransInetStatus.16."localhost6".10167.1 = 4
# fe80::1%em0:10168 - requires inet fe80::$em0/64
begemotSnmpdTransInetStatus.16."fe80::1%em0".10168.1 = 4
# fe80::1%em1:10169 - requires inet fe80::$em1/64
begemotSnmpdTransInetStatus.16."fe80::1%em1".10169.1 = 4
# open a unix domain socket
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
# begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
# begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
# send traps to the traphost
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
@ -103,12 +127,57 @@ snmpEnableAuthenTraps = 2
#
# Load MIB-2 module
#
#begemotSnmpdModulePath."mibII" = "../snmp_mibII/.libs/snmp_mibII.so"
begemotSnmpdModulePath."mibII" = "/usr/local/lib/snmp_mibII.so"
#
# SNMPv3 notification targets
#
#begemotSnmpdModulePath."target" = "../snmp_target/.libs/snmp_target.so"
begemotSnmpdModulePath."target" = "/usr/local/lib/snmp_target.so"
#
# SNMPv3 user-based security module
#
#begemotSnmpdModulePath."usm" = "../snmp_usm/.libs/snmp_usm.so"
begemotSnmpdModulePath."usm" = "/usr/local/lib/snmp_usm.so"
#
# SNMPv3 view-based access control module
#
#begemotSnmpdModulePath."vacm" = "../snmp_vacm/.libs/snmp_vacm.so"
begemotSnmpdModulePath."vacm" = "/usr/local/lib/snmp_vacm.so"
#
# Netgraph module
#
begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so"
# begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so"
# %netgraph
# begemotNgControlNodeName = "snmpd"
%vacm
internetoid := 1.3.6.1
internetoidlen := 4
vacmSecurityToGroupStatus.$(securityModelSNMPv1).$(read) = 4
vacmGroupName.$(securityModelSNMPv1).$(read) = $(read)
vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(read) = 4
vacmGroupName.$(securityModelSNMPv2c).$(read) = $(read)
vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(write) = 4
vacmGroupName.$(securityModelSNMPv2c).$(write) = $(write)
vacmViewTreeFamilyStatus."internet".$(internetoidlen).$(internetoid) = 4
vacmAccessStatus.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = 4
vacmAccessReadViewName.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = "internet"
vacmAccessStatus.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4
vacmAccessStatus.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4
vacmAccessReadViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet"
vacmAccessReadViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet"
vacmAccessWriteViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet"
vacmAccessWriteViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet"
%netgraph
begemotNgControlNodeName = "snmpd"

View file

@ -858,6 +858,7 @@ ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
sock->ret_source.a6.ipi6_ifindex =
!IN6_IS_ADDR_LINKLOCAL(&info->ipi6_addr) ? 0:
info->ipi6_ifindex;
} else if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDS) {
cred = (struct sockcred *)(void *)CMSG_DATA(cmsg);

1041
contrib/bsnmp/tests/asn1.cc Normal file

File diff suppressed because it is too large Load diff

17597
contrib/bsnmp/tests/catch.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,317 @@
/**
* Copyright (c) 2019-2020 Hartmut Brandt.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef constbuf_h_1578777513
#define constbuf_h_1578777513
#include <array>
#include <cassert>
#include <cstdint>
#if !defined(HAVE_EXPR_IN_ARRAY_SIZE) && (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>= 9 || (__GNUC__ == 9 && __GNUC_MINOR__ >= 1))))
#define HAVE_EXPR_IN_ARRAY_SIZE 1
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
#endif
#ifndef HAVE_EXPR_IN_ARRAY_SIZE
#include <vector>
#endif
namespace test {
namespace detail {
enum class Constbuf_mode {
BIN,
COMMENT,
HEX,
CHECK,
GOTO,
};
template<typename A>
constexpr bool
count_comment(A c, Constbuf_mode &mode)
{
if (c == '\n')
mode = Constbuf_mode::BIN;
return false;
}
template<typename A>
constexpr bool
count_hex(A c, Constbuf_mode &mode, std::size_t &bits)
{
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F')) {
if (bits % 4 != 0)
throw "unaligned hex digit";
bits += 4;
return false;
}
if (c == ':')
return false;
mode = Constbuf_mode::BIN;
return true;
}
template<typename A, typename U>
constexpr bool
handle_hex(A c, Constbuf_mode &mode, std::size_t &bit, U &n)
{
if (c >= '0' && c <= '9') {
n[bit / 8] |= ((c - '0') << 4) >> (bit % 8);
bit += 4;
return false;
}
if (c >= 'a' && c <= 'f') {
n[bit / 8] |= ((c - 'a' + 10) << 4) >> (bit % 8);
bit += 4;
return false;
}
if (c >= 'A' && c <= 'F') {
n[bit / 8] |= ((c - 'A' + 10) << 4) >> (bit % 8);
bit += 4;
return false;
}
if (c == ':')
return false;
mode = Constbuf_mode::BIN;
return true;
}
template<typename A>
constexpr bool
count_check(A c, Constbuf_mode &mode, std::size_t &)
{
if (c >= '0' && c <= '9')
return false;
mode = Constbuf_mode::BIN;
return true;
}
template<typename A>
constexpr bool
handle_check(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
{
if (c >= '0' && c <= '9') {
addr = 10 * addr + c - '0';
return false;
}
if (bits % 8 != 0 || bits / 8 != addr)
throw "address check failed";
mode = Constbuf_mode::BIN;
return true;
}
template<typename A>
constexpr bool
count_goto(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
{
if (c >= '0' && c <= '9') {
addr = 10 * addr + c - '0';
return false;
}
if (8 * addr < bits)
throw "cannot go backwards";
bits = 8 * addr;
mode = Constbuf_mode::BIN;
return true;
}
template<typename A>
constexpr bool
count_bin(A c, Constbuf_mode &mode, std::size_t &bits, std::size_t &addr)
{
if (c == ' ' || c == '\t' || c == '\n')
/* just ignore */
return false;
if (c == ';') {
mode = Constbuf_mode::COMMENT;
return false;
}
if (c == 'x' || c == 'X') {
mode = Constbuf_mode::HEX;
return false;
}
if (c == '!') {
mode = Constbuf_mode::CHECK;
return false;
}
if (c == '@') {
mode = Constbuf_mode::GOTO;
addr = 0;
return false;
}
if (c == '0' || c == '1' || c == '.') {
bits++;
return false;
}
throw "bad character";
}
template<typename A, typename U>
constexpr bool
handle_bin(A c, Constbuf_mode &mode, std::size_t &bit, std::size_t &addr, U &n)
{
if (c == ' ' || c == '\t' || c == '\n')
/* just ignore */
return false;
if (c == ';') {
mode = Constbuf_mode::COMMENT;
return false;
}
if (c == 'x' || c == 'X') {
mode = Constbuf_mode::HEX;
return false;
}
if (c == '!') {
mode = Constbuf_mode::CHECK;
addr = 0;
return false;
}
if (c == '@') {
mode = Constbuf_mode::GOTO;
addr = 0;
return false;
}
if (c == '0' || c == '.') {
bit++;
return false;
}
if (c == '1') {
n[bit / 8] |= 0x80 >> (bit % 8);
bit++;
return false;
}
throw "bad character";
}
/**
* Count the bits in the test buffer. For a syntax see below.
*
* \tparam A buffer base character type
* \tparam a characters
*
* \return number of bits required
*/
template<typename A, A ...a>
constexpr std::size_t
count_bits()
{
std::size_t bits {0};
std::size_t addr {0};
auto mode = Constbuf_mode::BIN;
for (auto c : {a...}) {
for (bool again = true; again; again = false) {
switch (mode) {
case Constbuf_mode::COMMENT:
again = count_comment(c, mode);
break;
case Constbuf_mode::CHECK:
again = count_check(c, mode, bits);
break;
case Constbuf_mode::GOTO:
again = count_goto(c, mode, bits, addr);
break;
case Constbuf_mode::HEX:
again = count_hex(c, mode, bits);
break;
case Constbuf_mode::BIN:
again = count_bin(c, mode, bits, addr);
break;
}
}
}
return bits;
}
}
template<typename A, A ...a>
#ifdef HAVE_EXPR_IN_ARRAY_SIZE
constexpr auto
#else
auto
#endif
constbuf()
{
#ifdef HAVE_EXPR_IN_ARRAY_SIZE
std::array<uint8_t, (detail::count_bits<A, a...>() + 7) / 8> n {};
#else
std::vector<uint8_t> n((detail::count_bits<A, a...>() + 7) / 8);
#endif
using namespace detail;
std::size_t bit {0};
std::size_t addr {0};
auto mode = Constbuf_mode::BIN;
for (auto c : {a...}) {
for (bool again = true; again; again = false) {
switch (mode) {
case Constbuf_mode::COMMENT:
again = count_comment(c, mode);
break;
case Constbuf_mode::CHECK:
again = handle_check(c, mode, bit, addr);
break;
case Constbuf_mode::GOTO:
again = count_goto(c, mode, bit, addr);
break;
case Constbuf_mode::HEX:
again = handle_hex(c, mode, bit, n);
break;
case Constbuf_mode::BIN:
again = handle_bin(c, mode, bit, addr, n);
break;
}
}
}
return n;
}
inline namespace literals {
inline namespace cbuf_literals {
#ifdef HAVE_EXPR_IN_ARRAY_SIZE
template<typename A, A ...a>
constexpr auto
#else
template<typename A, A ...a>
auto
#endif
operator ""_cbuf()
{
return test::constbuf<A, a...>();
}
} /* namespace cbuf_literals */
} /* namespace literals */
} /* namespace test */
#endif

View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View file

@ -0,0 +1,529 @@
#include <iostream>
#include <string>
extern "C" {
#include "asn1.h"
#include "snmp.h"
#include "snmpclient.h"
};
#include "catch.hpp"
using namespace std::string_literals;
static inline int
try_parse(struct snmp_client *sc, const char *str)
{
const int r = snmp_parse_server(sc, str);
if (false && r != 0)
std::cout << "snmp_parse_server: " << sc->error << "\n";
return r;
}
TEST_CASE("snmp_parse_server: empty string", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
REQUIRE(try_parse(&sc, "") == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == ""s);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
TEST_CASE("snmp_parse_server: hostname only", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("simple name without special characters") {
const auto str = "somehost"s;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == str);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("complex host name without special characters") {
const auto str = "some.host.domain"s;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == str);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("complex host name with special characters") {
const auto str = "some-mul.host-32.domain."s;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == str);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("relative path name") {
const auto str = "foo/bar"s;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
REQUIRE(sc.chost == str);
REQUIRE(sc.cport == ""s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("absolute path name") {
const auto str = "/foo/bar"s;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
REQUIRE(sc.chost == str);
REQUIRE(sc.cport == ""s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
}
TEST_CASE("snmp_parse_server: ipv6 address only", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("in6_addr_any") {
const auto host = "::"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("localhost") {
const auto host = "::1"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("link local address") {
const auto host = "fc00:0:12::1"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("illegal address (bad character)") {
const auto host = "fc00:0:1x::1"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == host + ": Name does not resolve");
}
SECTION("illegal address (two double colons)") {
const auto host = "fc00::0:12::1"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == host + ": Name does not resolve");
}
SECTION("illegal address (two many colons)") {
const auto host = "1:2:3:4:5:6:7:8:9"s;
const auto str = "[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == host + ": Name does not resolve");
}
SECTION("ipv6 address and junk") {
const auto host = "::"s;
const auto str = "[" + host + "]" + "xxx";
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == "junk at end of server specification 'xxx'"s);
}
}
TEST_CASE("snmp_parse_server: hostname and port", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("simple name and numeric port") {
const auto host = "somehost"s;
const auto port = "10007"s;
const auto str = host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("simple name and string port") {
const auto host = "somehost"s;
const auto port = "telnet"s;
const auto str = host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("name with embedded colon and numeric port") {
const auto host = "somehost:foo"s;
const auto port = "10007"s;
const auto str = host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("FQDN with embedded colon and numeric port") {
const auto host = "bla.blub:foo.baz."s;
const auto port = "10007"s;
const auto str = host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("simple name and empty port") {
const auto host = "somehost"s;
const auto port = ""s;
const auto str = host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == "empty port name"s);
}
}
TEST_CASE("snmp_parse_server: ipv6 and port", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("ANY address and numeric port") {
const auto host = "::"s;
const auto port = "10007"s;
const auto str = "[" + host + "]:" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("localhost address and string port") {
const auto host = "::1"s;
const auto port = "snmp"s;
const auto str = "[" + host + "]:" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("some address name and empty port") {
const auto host = "fc00:00:01::2:3"s;
const auto port = ""s;
const auto str = "[" + host + "]:" + port;
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == "empty port name"s);
}
}
TEST_CASE("snmp_parse_server: IPv4 address only", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("single octet address") {
const auto host = "127"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("two octet address") {
const auto host = "127.1"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("three octet address") {
const auto host = "127.23.1"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("four octet address") {
const auto host = "127.18.23.1"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("four octet octal address") {
const auto host = "0300.077.0377.01"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("four octet hex address") {
const auto host = "x80.x12.xff.x1"s;
const auto str = host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
}
TEST_CASE("snmp_parse_server: transport and hostname", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("udp and host") {
const auto trans = "udp"s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp and ipv4 address") {
const auto trans = "udp"s;
const auto host = "240.0.1.2"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp6 and host") {
const auto trans = "udp6"s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp6 and ipv6 address") {
const auto trans = "udp6"s;
const auto host = "fec0:0:2::17"s;
const auto str = trans + "::[" + host + "]";
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("dgram and host") {
const auto trans = "dgram"s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == ""s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("stream and host") {
const auto trans = "stream"s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_LOC_STREAM);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == ""s);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("unknown transport and host") {
const auto trans = "foo"s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == "unknown transport specifier '" + trans + "'");
}
SECTION("empty transport and host") {
const auto trans = ""s;
const auto host = "somehost"s;
const auto str = trans + "::" + host;
REQUIRE(try_parse(&sc, str.c_str()) == -1);
REQUIRE(sc.error == "empty transport specifier"s);
}
}
TEST_CASE("snmp_parse_server: transport, host and port", "[snmp_parse_server]") {
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("udp, host and port") {
const auto trans = "udp"s;
const auto host = "somehost"s;
const auto port = "ssh"s;
const auto str = trans + "::" + host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp, host with colon and port") {
const auto trans = "udp"s;
const auto host = "somehost:foo"s;
const auto port = "ssh"s;
const auto str = trans + "::" + host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp and port") {
const auto trans = "udp"s;
const auto host = ""s;
const auto port = "ssh"s;
const auto str = trans + "::" + host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
SECTION("udp6, ipv6 and port") {
const auto trans = "udp6"s;
const auto host = "::1:2"s;
const auto port = "ssh"s;
const auto str = trans + "::[" + host + "]:" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == "public"s);
REQUIRE(sc.write_community == "private"s);
}
}
TEST_CASE("snmp_parse_server: community and host", "[snmp_parse_server]")
{
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("community and host") {
const auto comm = "public"s;
const auto host = "server.com"s;
const auto str = comm + "@" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
SECTION("community with @ and host") {
const auto comm = "public@bla"s;
const auto host = "server.com"s;
const auto str = comm + "@" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
SECTION("empty community and host") {
const auto comm = ""s;
const auto host = "server.com"s;
const auto str = comm + "@" + host;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == "snmp"s);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
}
TEST_CASE("snmp_parse_server: transport, community, host and port", "[snmp_parse_server]")
{
struct snmp_client sc;
snmp_client_init(&sc);
SECTION("transport, community, host and numeric port") {
const auto trans = "udp6"s;
const auto comm = "public"s;
const auto host = "server.com"s;
const auto port = "65000"s;
const auto str = trans + "::" + comm + "@" + host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
SECTION("transport, community, ipv4 and symbolic port") {
const auto trans = "udp6"s;
const auto comm = "public"s;
const auto host = "127.1"s;
const auto port = "ftp"s;
const auto str = trans + "::" + comm + "@" + host + ":" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
SECTION("transport, community, ipv6 and symbolic port") {
const auto trans = "udp"s;
const auto comm = "public"s;
const auto host = "fe80::1:2"s;
const auto port = "ftp"s;
const auto str = trans + "::" + comm + "@[" + host + "]:" + port;
REQUIRE(try_parse(&sc, str.c_str()) == 0);
REQUIRE(sc.trans == SNMP_TRANS_UDP6);
REQUIRE(sc.chost == host);
REQUIRE(sc.cport == port);
REQUIRE(sc.read_community == comm);
REQUIRE(sc.write_community == comm);
}
}

View file

@ -14,6 +14,8 @@ LD_FATAL_WARNINGS= no
CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
CFLAGS+= -DBOGUS_CVE_2019_5610_FIX
.if ${MK_OPENSSL} != "no"
CFLAGS+= -DHAVE_LIBCRYPTO
LIBADD= crypto